Skip to content
Snippets Groups Projects
Commit a12f0254 authored by Jono Wenger's avatar Jono Wenger
Browse files

XX-3979 / Add callback system to E2E and add feature to send e2e message to partner on e2e close

parent 65365b4b
No related branches found
No related tags found
2 merge requests!510Release,!303XX-3979 / Add callback system to E2E and add feature to send e2e message to partner on e2e close
...@@ -150,5 +150,6 @@ type e2eHandler interface { ...@@ -150,5 +150,6 @@ type e2eHandler interface {
receiveParams session.Params) (partner.Manager, error) receiveParams session.Params) (partner.Manager, error)
GetPartner(partnerID *id.ID) (partner.Manager, error) GetPartner(partnerID *id.ID) (partner.Manager, error)
DeletePartner(partnerId *id.ID) error DeletePartner(partnerId *id.ID) error
DeletePartnerNotify(partnerId *id.ID, params e2e.Params) error
GetReceptionID() *id.ID GetReceptionID() *id.ID
} }
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
package auth package auth
import ( import (
"gitlab.com/elixxir/client/e2e"
"io" "io"
"math/rand" "math/rand"
"testing" "testing"
...@@ -100,6 +101,9 @@ func (me2e *mockE2E) GetPartner(partnerID *id.ID) (partner.Manager, error) { ...@@ -100,6 +101,9 @@ func (me2e *mockE2E) GetPartner(partnerID *id.ID) (partner.Manager, error) {
func (me2e *mockE2E) DeletePartner(partnerId *id.ID) error { func (me2e *mockE2E) DeletePartner(partnerId *id.ID) error {
return nil return nil
} }
func (me2e *mockE2E) DeletePartnerNotify(partnerId *id.ID, params e2e.Params) error {
return nil
}
func (me2e *mockE2E) GetReceptionID() *id.ID { func (me2e *mockE2E) GetReceptionID() *id.ID {
return me2e.reception return me2e.reception
} }
......
...@@ -105,6 +105,10 @@ func (m mockE2eHandler) DeletePartner(partnerId *id.ID) error { ...@@ -105,6 +105,10 @@ func (m mockE2eHandler) DeletePartner(partnerId *id.ID) error {
return nil return nil
} }
func (m mockE2eHandler) DeletePartnerNotify(partnerId *id.ID, params e2e.Params) error {
return nil
}
func (m mockE2eHandler) GetAllPartnerIDs() []*id.ID { func (m mockE2eHandler) GetAllPartnerIDs() []*id.ID {
return nil return nil
} }
...@@ -139,6 +143,18 @@ func (m mockE2eHandler) GetReceptionID() *id.ID { ...@@ -139,6 +143,18 @@ func (m mockE2eHandler) GetReceptionID() *id.ID {
return nil return nil
} }
func (m mockE2eHandler) RegisterCallbacks(callbacks e2e.Callbacks) {
panic("implement me")
}
func (m mockE2eHandler) AddPartnerCallbacks(partnerID *id.ID, cb e2e.Callbacks) {
panic("implement me")
}
func (m mockE2eHandler) DeletePartnerCallbacks(partnerID *id.ID) {
panic("implement me")
}
type mockSentRequestHandler struct{} type mockSentRequestHandler struct{}
func (msrh *mockSentRequestHandler) Add(sr *store.SentRequest) {} func (msrh *mockSentRequestHandler) Add(sr *store.SentRequest) {}
......
...@@ -32,6 +32,10 @@ const ( ...@@ -32,6 +32,10 @@ const (
// to confirm completion of a rekey. For ephemeral only e2e instances. // to confirm completion of a rekey. For ephemeral only e2e instances.
KeyExchangeConfirmEphemeral = 33 KeyExchangeConfirmEphemeral = 33
// E2eClose message is sent when a user deletes a partner and wants to
// inform their partner that the connection is closed.
E2eClose MessageType = 34
/* Group chat message types */ /* Group chat message types */
// GroupCreationRequest - A group chat request message sent to all members in a group. // GroupCreationRequest - A group chat request message sent to all members in a group.
...@@ -65,6 +69,8 @@ func (mt MessageType) String() string { ...@@ -65,6 +69,8 @@ func (mt MessageType) String() string {
return "KeyExchangeTriggerEphemeral" return "KeyExchangeTriggerEphemeral"
case KeyExchangeConfirmEphemeral: case KeyExchangeConfirmEphemeral:
return "KeyExchangeConfirmEphemeral" return "KeyExchangeConfirmEphemeral"
case E2eClose:
return "E2eClose"
case GroupCreationRequest: case GroupCreationRequest:
return "GroupCreationRequest" return "GroupCreationRequest"
case NewFileTransfer: case NewFileTransfer:
......
////////////////////////////////////////////////////////////////////////////////
// Copyright © 2020 xx network SEZC //
// //
// Use of this source code is governed by a license that can be found in the //
// LICENSE file //
////////////////////////////////////////////////////////////////////////////////
package e2e
import (
jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/client/cmix/rounds"
"gitlab.com/xx_network/primitives/id"
"sync"
)
// partnerCallbacks is a thread-safe wrapper for Callbacks specific to partner
// IDs. For E2E operations with a specific partner, these Callbacks will be used
// instead.
type partnerCallbacks struct {
callbacks map[id.ID]Callbacks
sync.RWMutex
}
// newPartnerCallbacks initializes an empty partnerCallbacks.
func newPartnerCallbacks() *partnerCallbacks {
return &partnerCallbacks{
callbacks: make(map[id.ID]Callbacks),
}
}
// add registers Callbacks that override the generic E2E callback for the given
// partner ID.
func (pcb *partnerCallbacks) add(partnerID *id.ID, cbs Callbacks) {
pcb.Lock()
defer pcb.Unlock()
pcb.callbacks[*partnerID] = cbs
}
// delete deletes the callbacks for the given partner ID.
func (pcb *partnerCallbacks) delete(partnerID *id.ID) {
pcb.Lock()
defer pcb.Unlock()
delete(pcb.callbacks, *partnerID)
}
// get returns the Callbacks for the given partner ID.
func (pcb *partnerCallbacks) get(partnerID *id.ID) Callbacks {
pcb.RLock()
defer pcb.RUnlock()
return pcb.callbacks[*partnerID]
}
// DefaultCallbacks is a simple structure for providing a default Callbacks
// implementation. It should generally not be used.
type DefaultCallbacks struct{}
func (d *DefaultCallbacks) ConnectionClosed(*id.ID, rounds.Round) {
jww.ERROR.Printf("No valid e2e callback assigned!")
}
////////////////////////////////////////////////////////////////////////////////
// Copyright © 2020 xx network SEZC //
// //
// Use of this source code is governed by a license that can be found in the //
// LICENSE file //
////////////////////////////////////////////////////////////////////////////////
package e2e
import (
"gitlab.com/elixxir/client/cmix/rounds"
"gitlab.com/xx_network/primitives/id"
"reflect"
"testing"
)
// Tests that newPartnerCallbacks returns the expected new partnerCallbacks.
func Test_newPartnerCallbacks(t *testing.T) {
expected := &partnerCallbacks{
callbacks: make(map[id.ID]Callbacks),
}
pcb := newPartnerCallbacks()
if !reflect.DeepEqual(expected, pcb) {
t.Errorf("Did not get expected new partnerCallbacks."+
"\nexpected: %+v\nreceived: %+v", expected, pcb)
}
}
// Tests that partnerCallbacks.add adds all the expected callbacks to the map.
func Test_partnerCallbacks_add(t *testing.T) {
pcb := newPartnerCallbacks()
const n = 10
expected := make(map[id.ID]Callbacks, n)
for i := uint64(0); i < n; i++ {
expected[*id.NewIdFromUInt(i, id.User, t)] = &mockCallbacks{id: i}
}
for partnerID, cbs := range expected {
pcb.add(&partnerID, cbs)
}
if !reflect.DeepEqual(expected, pcb.callbacks) {
t.Errorf("Callback list does not match expected."+
"\nexpected: %v\nreceived: %v", expected, pcb.callbacks)
}
}
// Tests that partnerCallbacks.delete removes all callbacks from the map.
func Test_partnerCallbacks_delete(t *testing.T) {
pcb := newPartnerCallbacks()
const n = 10
expected := make(map[id.ID]Callbacks, n)
for i := uint64(0); i < n; i++ {
partnerID, cbs := id.NewIdFromUInt(i, id.User, t), &mockCallbacks{id: i}
expected[*partnerID] = cbs
pcb.add(partnerID, cbs)
}
for partnerID := range expected {
pcb.delete(&partnerID)
}
if len(pcb.callbacks) > 0 {
t.Errorf("Callback map not empty: %v", pcb.callbacks)
}
}
// Tests that partnerCallbacks.get returns the expected Callbacks for each
// partner ID.
func Test_partnerCallbacks_get(t *testing.T) {
pcb := newPartnerCallbacks()
const n = 10
expected := make(map[id.ID]Callbacks, n)
for i := uint64(0); i < n; i++ {
partnerID, cbs := id.NewIdFromUInt(i, id.User, t), &mockCallbacks{id: i}
expected[*partnerID] = cbs
pcb.add(partnerID, cbs)
}
for partnerID, expectedCbs := range expected {
cbs := pcb.get(&partnerID)
if !reflect.DeepEqual(expectedCbs, cbs) {
t.Errorf("Callbacks for parter %s do not match."+
"\nexpected: %+v\nreceived: %+v", &partnerID, expectedCbs, cbs)
}
}
}
////////////////////////////////////////////////////////////////////////////////
// Mock Callbacks //
////////////////////////////////////////////////////////////////////////////////
// Verify that mockCallbacks adhere to the Callbacks interface
var _ Callbacks = (*mockCallbacks)(nil)
// mockCallbacks is a structure used for testing that adheres to the Callbacks
// interface.
type mockCallbacks struct {
id uint64
connectionClosedChan chan *id.ID
}
func (m *mockCallbacks) ConnectionClosed(partner *id.ID, _ rounds.Round) {
m.connectionClosedChan <- partner
}
package e2e package e2e
import ( import (
"gitlab.com/elixxir/client/cmix/rounds"
"time" "time"
"github.com/cloudflare/circl/dh/sidh" "github.com/cloudflare/circl/dh/sidh"
...@@ -121,10 +122,15 @@ type Handler interface { ...@@ -121,10 +122,15 @@ type Handler interface {
// GetPartner returns the partner per its ID, if it exists // GetPartner returns the partner per its ID, if it exists
GetPartner(partnerID *id.ID) (partner.Manager, error) GetPartner(partnerID *id.ID) (partner.Manager, error)
// DeletePartner removes the associated contact from the E2E store // DeletePartner removes the contact associated with the partnerId from the
// myID is your ID in the relationship // E2E store.
DeletePartner(partnerId *id.ID) error DeletePartner(partnerId *id.ID) error
// DeletePartnerNotify removes the contact associated with the partnerId
// from the E2E store. It then sends a critical E2E message to the partner
// informing them that the E2E connection is closed.
DeletePartnerNotify(partnerId *id.ID, params Params) error
// GetAllPartnerIDs returns a list of all partner IDs that the user has // GetAllPartnerIDs returns a list of all partner IDs that the user has
// an E2E relationship with. // an E2E relationship with.
GetAllPartnerIDs() []*id.ID GetAllPartnerIDs() []*id.ID
...@@ -149,6 +155,31 @@ type Handler interface { ...@@ -149,6 +155,31 @@ type Handler interface {
// RemoveService removes all services for the given tag // RemoveService removes all services for the given tag
RemoveService(tag string) error RemoveService(tag string) error
/* === Callbacks ==================================================== */
// The E2E callbacks are a set of callbacks that are called in specific
// situations. For example, ConnectionClosed is called when you receive a
// message from a partner informing you they have deleted the partnership.
//
// By default, on E2E creation, callbacks are not set and no action is
// taken. To set generic callbacks, that is used for all partners, use
// RegisterCallbacks. Specific callbacks can be registered per user that are
// used instead of the generic ones.
// RegisterCallbacks registers a generic Callbacks. This function overwrites
// any previously saved Callbacks. By default, these callbacks are nil and
// ignored until set via this function.
RegisterCallbacks(callbacks Callbacks)
// AddPartnerCallbacks registers a new Callbacks that overrides the generic
// E2E callbacks for the given partner ID.
AddPartnerCallbacks(partnerID *id.ID, cb Callbacks)
// DeletePartnerCallbacks deletes the Callbacks that override the generic
// E2E callback for the given partner ID. Deleting these callbacks will
// result in the generic E2E callbacks being used.
DeletePartnerCallbacks(partnerID *id.ID)
/* === Unsafe ======================================================= */ /* === Unsafe ======================================================= */
// SendUnsafe sends a message without encryption. It breaks // SendUnsafe sends a message without encryption. It breaks
...@@ -198,3 +229,12 @@ type Handler interface { ...@@ -198,3 +229,12 @@ type Handler interface {
// message // message
PayloadSize() uint PayloadSize() uint
} }
// Callbacks contains the possible callbacks on E2E.
type Callbacks interface {
// ConnectionClosed is called when you receive a message from a partner
// informing you that they have deleted the partnership and will no longer
// receive messages. It is called when a catalog.E2eClose E2E message is
// received.
ConnectionClosed(partner *id.ID, round rounds.Round)
}
package e2e package e2e
import ( import (
"bytes"
"encoding/base64"
"encoding/json" "encoding/json"
"sync"
"time" "time"
jww "github.com/spf13/jwalterweatherman" jww "github.com/spf13/jwalterweatherman"
...@@ -37,6 +40,14 @@ type manager struct { ...@@ -37,6 +40,14 @@ type manager struct {
crit *critical crit *critical
rekeyParams rekey.Params rekeyParams rekey.Params
kv *versioned.KV kv *versioned.KV
// Generic Callbacks for all E2E operations; by default this is nil and
// ignored until set via RegisterCallbacks
callbacks Callbacks
cbMux sync.Mutex
// Partner-specific Callbacks
partnerCallbacks *partnerCallbacks
} }
const legacyE2EKey = "legacyE2ESystem" const legacyE2EKey = "legacyE2ESystem"
...@@ -146,6 +157,8 @@ func loadE2E(kv *versioned.KV, net cmix.Client, myDefaultID *id.ID, ...@@ -146,6 +157,8 @@ func loadE2E(kv *versioned.KV, net cmix.Client, myDefaultID *id.ID,
grp: grp, grp: grp,
rekeyParams: rekey.Params{}, rekeyParams: rekey.Params{},
kv: kv, kv: kv,
callbacks: nil,
partnerCallbacks: newPartnerCallbacks(),
} }
var err error var err error
...@@ -166,9 +179,22 @@ func loadE2E(kv *versioned.KV, net cmix.Client, myDefaultID *id.ID, ...@@ -166,9 +179,22 @@ func loadE2E(kv *versioned.KV, net cmix.Client, myDefaultID *id.ID,
"Failed to unmarshal rekeyParams data") "Failed to unmarshal rekeyParams data")
} }
// Register listener that calls the ConnectionClosed callback when a
// catalog.E2eClose message is received
m.Switchboard.RegisterFunc(
"connectionClosing", &id.ZeroUser, catalog.E2eClose, m.closeE2eListener)
return m, nil return m, nil
} }
// RegisterCallbacks registers the Callbacks to E2E. This function overwrite any
// previously saved Callbacks.
func (m *manager) RegisterCallbacks(callbacks Callbacks) {
m.cbMux.Lock()
defer m.cbMux.Unlock()
m.callbacks = callbacks
}
func (m *manager) StartProcesses() (stoppable.Stoppable, error) { func (m *manager) StartProcesses() (stoppable.Stoppable, error) {
multi := stoppable.NewMulti("e2eManager") multi := stoppable.NewMulti("e2eManager")
...@@ -206,6 +232,120 @@ func (m *manager) StartProcesses() (stoppable.Stoppable, error) { ...@@ -206,6 +232,120 @@ func (m *manager) StartProcesses() (stoppable.Stoppable, error) {
return multi, nil return multi, nil
} }
// DeletePartner removes the contact associated with the partnerId from the E2E
// store.
func (m *manager) DeletePartner(partnerId *id.ID) error {
err := m.Ratchet.DeletePartner(partnerId)
if err != nil {
return err
}
m.DeletePartnerCallbacks(partnerId)
return m.Ratchet.DeletePartner(partnerId)
}
// DeletePartnerNotify removes the contact associated with the partnerId
// from the E2E store. It then sends a critical E2E message to the partner
// informing them that the E2E connection is closed.
func (m *manager) DeletePartnerNotify(partnerId *id.ID, params Params) error {
// Check if the partner exists
p, err := m.GetPartner(partnerId)
if err != nil {
return err
}
// Enable critical message sending
params.Critical = true
// Setting the connection fingerprint as the payload allows the receiver
// to verify that this catalog.E2eClose message is from this specific
// E2E relationship. However, this is not strictly necessary since this
// message should not be received by any future E2E connection with the
// same partner. This is done as a sanity check and to plainly show
// which relationship this message belongs to.
payload := p.ConnectionFingerprint().Bytes()
// Prepare an E2E message informing the partner that you are closing the E2E
// connection. The send is prepared before deleting the partner because the
// partner needs to be available to build the E2E message. The message is
// not sent first to avoid sending the partner an erroneous message of
// deletion fails.
sendFunc, err := m.prepareSendE2E(
catalog.E2eClose, partnerId, payload, params)
if err != nil {
return err
}
err = m.Ratchet.DeletePartner(partnerId)
if err != nil {
return err
}
m.DeletePartnerCallbacks(partnerId)
// Send closing E2E message
rounds, msgID, timestamp, err := sendFunc()
if err != nil {
jww.ERROR.Printf("Failed to send %s E2E message to %s: %+v",
catalog.E2eClose, partnerId, err)
} else {
jww.INFO.Printf(
"Sent %s E2E message to %s on rounds %v with message ID %s at %s",
catalog.E2eClose, partnerId, rounds, msgID, timestamp)
}
return nil
}
// closeE2eListener calls the ConnectionClose callback when a catalog.E2eClose
// message is received from a partner.
func (m *manager) closeE2eListener(item receive.Message) {
p, err := m.GetPartner(item.Sender)
if err != nil {
jww.ERROR.Printf("Could not find sender %s of %s message: %+v",
item.Sender, catalog.E2eClose, err)
return
}
// Check the connection fingerprint to verify that the message is
// from the expected E2E relationship (refer to the comment in
// DeletePartner for more details)
if !bytes.Equal(p.ConnectionFingerprint().Bytes(), item.Payload) {
jww.ERROR.Printf("Received %s message from %s with incorrect "+
"connection fingerprint %s.", catalog.E2eClose, item.Sender,
base64.StdEncoding.EncodeToString(item.Payload))
return
}
jww.INFO.Printf("Received %s message from %s for relationship %s. "+
"Calling ConnectionClosed callback.",
catalog.E2eClose, item.Sender, p.ConnectionFingerprint())
if cb := m.partnerCallbacks.get(item.Sender); cb != nil {
cb.ConnectionClosed(item.Sender, item.Round)
} else if m.callbacks != nil {
m.cbMux.Lock()
m.callbacks.ConnectionClosed(item.Sender, item.Round)
m.cbMux.Unlock()
} else {
jww.INFO.Printf("No ConnectionClosed callback found.")
}
}
// AddPartnerCallbacks registers a new Callbacks that overrides the generic
// e2e callbacks for the given partner ID.
func (m *manager) AddPartnerCallbacks(partnerID *id.ID, cb Callbacks) {
m.partnerCallbacks.add(partnerID, cb)
}
// DeletePartnerCallbacks deletes the Callbacks that override the generic
// e2e callback for the given partner ID. Deleting these callbacks will
// result in the generic e2e callbacks being used.
func (m *manager) DeletePartnerCallbacks(partnerID *id.ID) {
m.partnerCallbacks.delete(partnerID)
}
// EnableUnsafeReception enables the reception of unsafe message by registering // EnableUnsafeReception enables the reception of unsafe message by registering
// bespoke services for reception. For debugging only! // bespoke services for reception. For debugging only!
func (m *manager) EnableUnsafeReception() { func (m *manager) EnableUnsafeReception() {
......
...@@ -44,15 +44,26 @@ func (m *manager) SendE2E(mt catalog.MessageType, recipient *id.ID, ...@@ -44,15 +44,26 @@ func (m *manager) SendE2E(mt catalog.MessageType, recipient *id.ID,
} }
func (m *manager) sendE2E(mt catalog.MessageType, recipient *id.ID, // sendE2eFn contains a prepared sendE2E operation and sends an E2E message when
payload []byte, params Params) ([]id.Round, e2e.MessageID, time.Time, error) { // called, returning the results of the send.
type sendE2eFn func() ([]id.Round, e2e.MessageID, time.Time, error)
// prepareSendE2E makes a prepared function that does the e2e send.
// This is so that when doing deletePartner we can prepare the send before
// deleting and then send after deleting to ensure there is correctness.
//
// Note: the timestamp in the send is recorded in this call, not when the
// sendE2e function is called.
func (m *manager) prepareSendE2E(mt catalog.MessageType, recipient *id.ID,
payload []byte, params Params) (sendE2E sendE2eFn, err error) {
ts := netTime.Now() ts := netTime.Now()
sendFuncs := make([]func(), 0)
partitions, internalMsgId, err := m.partitioner.Partition(recipient, partitions, internalMsgId, err := m.partitioner.Partition(recipient,
mt, ts, payload) mt, ts, payload)
if err != nil { if err != nil {
return nil, e2e.MessageID{}, time.Time{}, return nil, errors.WithMessage(err, "failed to send unsafe message")
errors.WithMessage(err, "failed to send unsafe message")
} }
jww.INFO.Printf("E2E sending %d messages to %s", len(partitions), recipient) jww.INFO.Printf("E2E sending %d messages to %s", len(partitions), recipient)
...@@ -66,7 +77,7 @@ func (m *manager) sendE2E(mt catalog.MessageType, recipient *id.ID, ...@@ -66,7 +77,7 @@ func (m *manager) sendE2E(mt catalog.MessageType, recipient *id.ID,
// key negotiated for the ratchet // key negotiated for the ratchet
partner, err := m.Ratchet.GetPartner(recipient) partner, err := m.Ratchet.GetPartner(recipient)
if err != nil { if err != nil {
return nil, e2e.MessageID{}, time.Time{}, errors.WithMessagef(err, return nil, errors.WithMessagef(err,
"cannot send E2E message no relationship found with %s", recipient) "cannot send E2E message no relationship found with %s", recipient)
} }
...@@ -101,7 +112,7 @@ func (m *manager) sendE2E(mt catalog.MessageType, recipient *id.ID, ...@@ -101,7 +112,7 @@ func (m *manager) sendE2E(mt catalog.MessageType, recipient *id.ID,
keyGetter, params.KeyGetRetryCount, params.KeyGeRetryDelay, keyGetter, params.KeyGetRetryCount, params.KeyGeRetryDelay,
params.Stop, recipient, format.DigestContents(p), i) params.Stop, recipient, format.DigestContents(p), i)
if err != nil { if err != nil {
return nil, e2e.MessageID{}, time.Time{}, errors.WithMessagef(err, return nil, errors.WithMessagef(err,
"Failed to get key for end-to-end encryption") "Failed to get key for end-to-end encryption")
} }
...@@ -123,6 +134,8 @@ func (m *manager) sendE2E(mt catalog.MessageType, recipient *id.ID, ...@@ -123,6 +134,8 @@ func (m *manager) sendE2E(mt catalog.MessageType, recipient *id.ID,
// We send each partition in its own thread here; some may send in round // We send each partition in its own thread here; some may send in round
// X, others in X+1 or X+2, and so on // X, others in X+1 or X+2, and so on
localI := i
thisSendFunc := func() {
wg.Add(1) wg.Add(1)
go func(i int) { go func(i int) {
var err error var err error
...@@ -132,7 +145,14 @@ func (m *manager) sendE2E(mt catalog.MessageType, recipient *id.ID, ...@@ -132,7 +145,14 @@ func (m *manager) sendE2E(mt catalog.MessageType, recipient *id.ID,
errCh <- err errCh <- err
} }
wg.Done() wg.Done()
}(i) }(localI)
}
sendFuncs = append(sendFuncs, thisSendFunc)
}
sendE2E = func() ([]id.Round, e2e.MessageID, time.Time, error) {
for i := range sendFuncs {
sendFuncs[i]()
} }
wg.Wait() wg.Wait()
...@@ -154,6 +174,17 @@ func (m *manager) sendE2E(mt catalog.MessageType, recipient *id.ID, ...@@ -154,6 +174,17 @@ func (m *manager) sendE2E(mt catalog.MessageType, recipient *id.ID,
return roundIds, msgID, ts, nil return roundIds, msgID, ts, nil
} }
return sendE2E, nil
}
func (m *manager) sendE2E(mt catalog.MessageType, recipient *id.ID,
payload []byte, params Params) ([]id.Round, e2e.MessageID, time.Time, error) {
sendFunc, err := m.prepareSendE2E(mt, recipient, payload, params)
if err != nil {
return nil, e2e.MessageID{}, time.Time{}, err
}
return sendFunc()
}
// waitForKey waits the designated amount of time for a key to become available // waitForKey waits the designated amount of time for a key to become available
// with the partner. // with the partner.
......
...@@ -290,6 +290,7 @@ func (m *mockE2e) AddPartner(*id.ID, *cyclic.Int, *cyclic.Int, *sidh.PublicKey, ...@@ -290,6 +290,7 @@ func (m *mockE2e) AddPartner(*id.ID, *cyclic.Int, *cyclic.Int, *sidh.PublicKey,
} }
func (m *mockE2e) GetPartner(*id.ID) (partner.Manager, error) { panic("implement me") } func (m *mockE2e) GetPartner(*id.ID) (partner.Manager, error) { panic("implement me") }
func (m *mockE2e) DeletePartner(*id.ID) error { panic("implement me") } func (m *mockE2e) DeletePartner(*id.ID) error { panic("implement me") }
func (m *mockE2e) DeletePartnerNotify(*id.ID, e2e.Params) error { panic("implement me") }
func (m *mockE2e) GetAllPartnerIDs() []*id.ID { panic("implement me") } func (m *mockE2e) GetAllPartnerIDs() []*id.ID { panic("implement me") }
func (m *mockE2e) HasAuthenticatedChannel(*id.ID) bool { panic("implement me") } func (m *mockE2e) HasAuthenticatedChannel(*id.ID) bool { panic("implement me") }
func (m *mockE2e) AddService(string, message.Processor) error { panic("implement me") } func (m *mockE2e) AddService(string, message.Processor) error { panic("implement me") }
...@@ -306,6 +307,9 @@ func (m *mockE2e) FirstPartitionSize() uint { panic("implement me") } ...@@ -306,6 +307,9 @@ func (m *mockE2e) FirstPartitionSize() uint { panic("implement me") }
func (m *mockE2e) SecondPartitionSize() uint { panic("implement me") } func (m *mockE2e) SecondPartitionSize() uint { panic("implement me") }
func (m *mockE2e) PartitionSize(uint) uint { panic("implement me") } func (m *mockE2e) PartitionSize(uint) uint { panic("implement me") }
func (m *mockE2e) PayloadSize() uint { panic("implement me") } func (m *mockE2e) PayloadSize() uint { panic("implement me") }
func (m *mockE2e) RegisterCallbacks(e2e.Callbacks) { panic("implement me") }
func (m *mockE2e) AddPartnerCallbacks(*id.ID, e2e.Callbacks) { panic("implement me") }
func (m *mockE2e) DeletePartnerCallbacks(*id.ID) { panic("implement me") }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Mock Storage Session // // Mock Storage Session //
......
...@@ -97,6 +97,16 @@ func (*testE2eManager) AddService(string, message.Processor) error { ...@@ -97,6 +97,16 @@ func (*testE2eManager) AddService(string, message.Processor) error {
// Unused & unimplemented methods of the test object //////////////////////////////// // Unused & unimplemented methods of the test object ////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////
func (tnm *testE2eManager) DeletePartner(partnerId *id.ID) error {
// TODO implement me
panic("implement me")
}
func (tnm *testE2eManager) DeletePartnerNotify(partnerId *id.ID, params clientE2E.Params) error {
// TODO implement me
panic("implement me")
}
func (*testE2eManager) GetDefaultHistoricalDHPubkey() *cyclic.Int { func (*testE2eManager) GetDefaultHistoricalDHPubkey() *cyclic.Int {
panic("implement me") panic("implement me")
} }
...@@ -130,7 +140,17 @@ func (tnm *testE2eManager) UnregisterUserListeners(userID *id.ID) { ...@@ -130,7 +140,17 @@ func (tnm *testE2eManager) UnregisterUserListeners(userID *id.ID) {
panic("implement me") panic("implement me")
} }
func (tnm *testE2eManager) DeletePartner(partnerId *id.ID) error { func (tnm *testE2eManager) RegisterCallbacks(callbacks clientE2E.Callbacks) {
// TODO implement me
panic("implement me")
}
func (tnm *testE2eManager) AddPartnerCallbacks(partnerID *id.ID, cb clientE2E.Callbacks) {
// TODO implement me
panic("implement me")
}
func (tnm *testE2eManager) DeletePartnerCallbacks(partnerID *id.ID) {
// TODO implement me // TODO implement me
panic("implement me") panic("implement me")
} }
......
...@@ -99,6 +99,11 @@ func (m mockE2e) GetStorage() storage.Session { ...@@ -99,6 +99,11 @@ func (m mockE2e) GetStorage() storage.Session {
type mockE2eHandler struct{} type mockE2eHandler struct{}
func (m mockE2eHandler) RegisterCallbacks(callbacks e2e.Callbacks) {
// TODO implement me
panic("implement me")
}
func (m mockE2eHandler) StartProcesses() (stoppable.Stoppable, error) { func (m mockE2eHandler) StartProcesses() (stoppable.Stoppable, error) {
//TODO implement me //TODO implement me
panic("implement me") panic("implement me")
...@@ -149,6 +154,21 @@ func (m mockE2eHandler) DeletePartner(partnerId *id.ID) error { ...@@ -149,6 +154,21 @@ func (m mockE2eHandler) DeletePartner(partnerId *id.ID) error {
panic("implement me") panic("implement me")
} }
func (tnm mockE2eHandler) DeletePartnerNotify(partnerId *id.ID, params e2e.Params) error {
// TODO implement me
panic("implement me")
}
func (m mockE2eHandler) AddPartnerCallbacks(partnerID *id.ID, cb e2e.Callbacks) {
// TODO implement me
panic("implement me")
}
func (m mockE2eHandler) DeletePartnerCallbacks(partnerID *id.ID) {
// TODO implement me
panic("implement me")
}
func (m mockE2eHandler) GetAllPartnerIDs() []*id.ID { func (m mockE2eHandler) GetAllPartnerIDs() []*id.ID {
//TODO implement me //TODO implement me
panic("implement me") panic("implement me")
......
...@@ -320,6 +320,34 @@ func (m *E2e) DeleteContact(partnerId *id.ID) error { ...@@ -320,6 +320,34 @@ func (m *E2e) DeleteContact(partnerId *id.ID) error {
return nil return nil
} }
// DeleteContactNotify removes a partner from E2e's storage and sends an E2E
// message to the contact notifying them.
func (m *E2e) DeleteContactNotify(partnerId *id.ID, params e2e.Params) error {
jww.DEBUG.Printf("Deleting contact with ID %s", partnerId)
_, err := m.e2e.GetPartner(partnerId)
if err != nil {
return errors.WithMessagef(err, "Could not delete %s because "+
"they could not be found", partnerId)
}
if err = m.e2e.DeletePartnerNotify(partnerId, params); err != nil {
return err
}
m.backup.TriggerBackup("contact deleted")
// FIXME: Do we need this?
// c.e2e.Conversations().Delete(partnerId)
// call delete requests to make sure nothing is lingering.
// this is for safety to ensure the contact can be re-added
// in the future
_ = m.auth.DeleteRequest(partnerId)
return nil
}
// MakeAuthCallbacksAdapter creates an authCallbacksAdapter. // MakeAuthCallbacksAdapter creates an authCallbacksAdapter.
func MakeAuthCallbacksAdapter(ac AuthCallbacks, e2e *E2e) *authCallbacksAdapter { func MakeAuthCallbacksAdapter(ac AuthCallbacks, e2e *E2e) *authCallbacksAdapter {
return &authCallbacksAdapter{ return &authCallbacksAdapter{
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment