Handle allowedContact lists

This commit is contained in:
Andrea Maria Piana 2020-07-17 14:29:51 +02:00
parent 12a3c5a31a
commit bec8fbb855
No known key found for this signature in database
GPG Key ID: AA6CCA6DE0E06424
3 changed files with 124 additions and 22 deletions

View File

@ -3071,16 +3071,12 @@ func (m *Messenger) EnableSendingPushNotifications() error {
return nil return nil
} }
// RegisterForPushNotification register deviceToken with any push notification server enabled func (m *Messenger) addedContactsAndMutedChatIDs() ([]*ecdsa.PublicKey, []string) {
func (m *Messenger) RegisterForPushNotifications(ctx context.Context, deviceToken string) error {
if m.pushNotificationClient == nil {
return errors.New("push notification client not enabled")
}
var contactIDs []*ecdsa.PublicKey var contactIDs []*ecdsa.PublicKey
var mutedChatIDs []string var mutedChatIDs []string
m.mutex.Lock() m.mutex.Lock()
defer m.mutex.Unlock()
for _, contact := range m.allContacts { for _, contact := range m.allContacts {
if contact.IsAdded() { if contact.IsAdded() {
pk, err := contact.PublicKey() pk, err := contact.PublicKey()
@ -3099,7 +3095,16 @@ func (m *Messenger) RegisterForPushNotifications(ctx context.Context, deviceToke
} }
} }
m.mutex.Unlock() return contactIDs, mutedChatIDs
}
// RegisterForPushNotification register deviceToken with any push notification server enabled
func (m *Messenger) RegisterForPushNotifications(ctx context.Context, deviceToken string) error {
if m.pushNotificationClient == nil {
return errors.New("push notification client not enabled")
}
contactIDs, mutedChatIDs := m.addedContactsAndMutedChatIDs()
return m.pushNotificationClient.Register(deviceToken, contactIDs, mutedChatIDs) return m.pushNotificationClient.Register(deviceToken, contactIDs, mutedChatIDs)
} }
@ -3115,7 +3120,8 @@ func (m *Messenger) EnablePushNotificationsFromContactsOnly() error {
return errors.New("no push notification client") return errors.New("no push notification client")
} }
return m.pushNotificationClient.EnablePushNotificationsFromContactsOnly() contactIDs, mutedChatIDs := m.addedContactsAndMutedChatIDs()
return m.pushNotificationClient.EnablePushNotificationsFromContactsOnly(contactIDs, mutedChatIDs)
} }
func (m *Messenger) DisablePushNotificationsFromContactsOnly() error { func (m *Messenger) DisablePushNotificationsFromContactsOnly() error {
@ -3123,7 +3129,8 @@ func (m *Messenger) DisablePushNotificationsFromContactsOnly() error {
return errors.New("no push notification client") return errors.New("no push notification client")
} }
return m.pushNotificationClient.DisablePushNotificationsFromContactsOnly() contactIDs, mutedChatIDs := m.addedContactsAndMutedChatIDs()
return m.pushNotificationClient.DisablePushNotificationsFromContactsOnly(contactIDs, mutedChatIDs)
} }
func (m *Messenger) GetPushNotificationServers() ([]*push_notification_client.PushNotificationServer, error) { func (m *Messenger) GetPushNotificationServers() ([]*push_notification_client.PushNotificationServer, error) {

View File

@ -75,9 +75,9 @@ type Config struct {
// RemoteNotificationsEnabled is whether we should register with a remote server for push notifications // RemoteNotificationsEnabled is whether we should register with a remote server for push notifications
RemoteNotificationsEnabled bool RemoteNotificationsEnabled bool
// AllowyFromContactsOnly indicates whether we should be receiving push notifications // allowyFromContactsOnly indicates whether we should be receiving push notifications
// only from contacts // only from contacts
AllowFromContactsOnly bool allowFromContactsOnly bool
// InstallationID is the installation-id for this device // InstallationID is the installation-id for this device
InstallationID string InstallationID string
@ -101,8 +101,8 @@ type Client struct {
// AccessToken is the access token that is currently being used // AccessToken is the access token that is currently being used
AccessToken string AccessToken string
// DeviceToken is the device token for this device // deviceToken is the device token for this device
DeviceToken string deviceToken string
// randomReader only used for testing so we have deterministic encryption // randomReader only used for testing so we have deterministic encryption
reader io.Reader reader io.Reader
@ -156,6 +156,7 @@ func (c *Client) loadLastPushNotificationRegistration() error {
} }
c.lastContactIDs = lastContactIDs c.lastContactIDs = lastContactIDs
c.lastPushNotificationRegistration = lastRegistration c.lastPushNotificationRegistration = lastRegistration
c.deviceToken = lastRegistration.Token
return nil return nil
} }
@ -407,10 +408,30 @@ func (p *Client) encryptToken(publicKey *ecdsa.PublicKey, token []byte) ([]byte,
return encryptedToken, nil return encryptedToken, nil
} }
func (p *Client) allowedUserList(token []byte, contactIDs []*ecdsa.PublicKey) ([][]byte, error) { func (p *Client) decryptToken(publicKey *ecdsa.PublicKey, token []byte) ([]byte, error) {
sharedKey, err := ecies.ImportECDSA(p.config.Identity).GenerateShared(
ecies.ImportECDSAPublic(publicKey),
accessTokenKeyLength,
accessTokenKeyLength,
)
if err != nil {
return nil, err
}
decryptedToken, err := common.Decrypt(token, sharedKey)
if err != nil {
return nil, err
}
return decryptedToken, nil
}
func (c *Client) allowedUserList(token []byte, contactIDs []*ecdsa.PublicKey) ([][]byte, error) {
// If we allow everyone, don't set the list
if !c.config.allowFromContactsOnly {
return nil, nil
}
var encryptedTokens [][]byte var encryptedTokens [][]byte
for _, publicKey := range contactIDs { for _, publicKey := range contactIDs {
encryptedToken, err := p.encryptToken(publicKey, token) encryptedToken, err := c.encryptToken(publicKey, token)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -449,7 +470,7 @@ func (c *Client) buildPushNotificationRegistrationMessage(contactIDs []*ecdsa.Pu
TokenType: c.config.TokenType, TokenType: c.config.TokenType,
Version: c.getVersion(), Version: c.getVersion(),
InstallationId: c.config.InstallationID, InstallationId: c.config.InstallationID,
Token: c.DeviceToken, Token: c.deviceToken,
Enabled: c.config.RemoteNotificationsEnabled, Enabled: c.config.RemoteNotificationsEnabled,
BlockedChatList: c.mutedChatIDsHashes(mutedChatIDs), BlockedChatList: c.mutedChatIDsHashes(mutedChatIDs),
AllowedUserList: allowedUserList, AllowedUserList: allowedUserList,
@ -672,7 +693,7 @@ func (c *Client) Register(deviceToken string, contactIDs []*ecdsa.PublicKey, mut
// stop registration loop // stop registration loop
c.stopRegistrationLoop() c.stopRegistrationLoop()
c.DeviceToken = deviceToken c.deviceToken = deviceToken
registration, err := c.buildPushNotificationRegistrationMessage(contactIDs, mutedChatIDs) registration, err := c.buildPushNotificationRegistrationMessage(contactIDs, mutedChatIDs)
if err != nil { if err != nil {
@ -752,6 +773,18 @@ func (c *Client) handleGrant(clientPublicKey *ecdsa.PublicKey, serverPublicKey *
return nil return nil
} }
func (c *Client) handleAllowedUserList(publicKey *ecdsa.PublicKey, allowedUserList [][]byte) string {
for _, encryptedToken := range allowedUserList {
token, err := c.decryptToken(publicKey, encryptedToken)
if err != nil {
c.config.Logger.Warn("could not decrypt token", zap.Error(err))
continue
}
return string(token)
}
return ""
}
// HandlePushNotificationQueryResponse should update the data in the database for a given user // HandlePushNotificationQueryResponse should update the data in the database for a given user
func (c *Client) HandlePushNotificationQueryResponse(serverPublicKey *ecdsa.PublicKey, response protobuf.PushNotificationQueryResponse) error { func (c *Client) HandlePushNotificationQueryResponse(serverPublicKey *ecdsa.PublicKey, response protobuf.PushNotificationQueryResponse) error {
@ -775,6 +808,18 @@ func (c *Client) HandlePushNotificationQueryResponse(serverPublicKey *ecdsa.Publ
continue continue
} }
accessToken := info.AccessToken
if len(info.AllowedUserList) != 0 {
accessToken = c.handleAllowedUserList(publicKey, info.AllowedUserList)
}
if len(accessToken) == 0 {
c.config.Logger.Info("not in the allowed users list")
continue
}
// We check the user has allowed this server to store this particular // We check the user has allowed this server to store this particular
// access token, otherwise anyone could reply with a fake token // access token, otherwise anyone could reply with a fake token
// and receive notifications for a user // and receive notifications for a user
@ -881,13 +926,19 @@ func (c *Client) DisableSending() {
c.config.SendEnabled = false c.config.SendEnabled = false
} }
func (c *Client) EnablePushNotificationsFromContactsOnly() error { func (c *Client) EnablePushNotificationsFromContactsOnly(contactIDs []*ecdsa.PublicKey, mutedChatIDs []string) error {
c.config.AllowFromContactsOnly = true c.config.allowFromContactsOnly = true
if c.lastPushNotificationRegistration != nil {
return c.Register(c.deviceToken, contactIDs, mutedChatIDs)
}
return nil return nil
} }
func (c *Client) DisablePushNotificationsFromContactsOnly() error { func (c *Client) DisablePushNotificationsFromContactsOnly(contactIDs []*ecdsa.PublicKey, mutedChatIDs []string) error {
c.config.AllowFromContactsOnly = false c.config.allowFromContactsOnly = false
if c.lastPushNotificationRegistration != nil {
return c.Register(c.deviceToken, contactIDs, mutedChatIDs)
}
return nil return nil
} }

View File

@ -79,6 +79,49 @@ func (s *ClientSuite) TestBuildPushNotificationRegisterMessage() {
// Get token // Get token
expectedUUID := uuid.New().String() expectedUUID := uuid.New().String()
// Reset random generator
uuid.SetRand(rand.New(rand.NewSource(seed)))
s.client.deviceToken = myDeviceToken
// Set reader
s.client.reader = bytes.NewReader([]byte(expectedUUID))
options := &protobuf.PushNotificationRegistration{
Version: 1,
AccessToken: expectedUUID,
Token: myDeviceToken,
InstallationId: s.installationID,
Enabled: true,
BlockedChatList: mutedChatListHashes,
}
actualMessage, err := s.client.buildPushNotificationRegistrationMessage(contactIDs, mutedChatList)
s.Require().NoError(err)
s.Require().Equal(options, actualMessage)
}
func (s *ClientSuite) TestBuildPushNotificationRegisterMessageAllowFromContactsOnly() {
myDeviceToken := "device-token"
mutedChatList := []string{"a", "b"}
// build chat lish hashes
var mutedChatListHashes [][]byte
for _, chatID := range mutedChatList {
mutedChatListHashes = append(mutedChatListHashes, common.Shake256([]byte(chatID)))
}
contactKey, err := crypto.GenerateKey()
s.Require().NoError(err)
contactIDs := []*ecdsa.PublicKey{&contactKey.PublicKey}
// Set random generator for uuid
var seed int64 = 1
uuid.SetRand(rand.New(rand.NewSource(seed)))
// Get token
expectedUUID := uuid.New().String()
// set up reader // set up reader
reader := bytes.NewReader([]byte(expectedUUID)) reader := bytes.NewReader([]byte(expectedUUID))
@ -95,7 +138,8 @@ func (s *ClientSuite) TestBuildPushNotificationRegisterMessage() {
// Reset random generator // Reset random generator
uuid.SetRand(rand.New(rand.NewSource(seed))) uuid.SetRand(rand.New(rand.NewSource(seed)))
s.client.DeviceToken = myDeviceToken s.client.config.allowFromContactsOnly = true
s.client.deviceToken = myDeviceToken
// Set reader // Set reader
s.client.reader = bytes.NewReader([]byte(expectedUUID)) s.client.reader = bytes.NewReader([]byte(expectedUUID))