diff --git a/account_export.go b/account_export.go
index b76ccce2..434b2c99 100644
--- a/account_export.go
+++ b/account_export.go
@@ -12,14 +12,11 @@ import (
"github.com/ipfs/go-cid"
cbornode "github.com/ipfs/go-ipld-cbor"
ipfs_interface "github.com/ipfs/interface-go-ipfs-core"
- "github.com/libp2p/go-libp2p/core/crypto"
- crypto_pb "github.com/libp2p/go-libp2p/core/crypto/pb"
mh "github.com/multiformats/go-multihash"
"go.uber.org/multierr"
"go.uber.org/zap"
orbitdb "berty.tech/go-orbit-db"
- "berty.tech/weshnet/pkg/cryptoutil"
"berty.tech/weshnet/pkg/errcode"
"berty.tech/weshnet/pkg/protocoltypes"
)
@@ -35,11 +32,7 @@ func (s *service) export(ctx context.Context, output io.Writer) error {
tw := tar.NewWriter(output)
defer tw.Close()
- if err := s.exportAccountKey(tw); err != nil {
- return errcode.ErrInternal.Wrap(err)
- }
-
- if err := s.exportAccountProofKey(tw); err != nil {
+ if err := s.exportAccountKeys(tw); err != nil {
return errcode.ErrInternal.Wrap(err)
}
@@ -109,22 +102,23 @@ func (s *service) exportOrbitDBStore(ctx context.Context, store orbitdb.Store, t
return nil
}
-func (s *service) exportAccountKey(tw *tar.Writer) error {
- sk, err := s.deviceKeystore.AccountPrivKey()
+func (s *service) exportAccountKeys(tw *tar.Writer) error {
+ accountPrivateKeyBytes, accountProofPrivateKeyBytes, err := s.secretStore.ExportAccountKeysForBackup()
if err != nil {
return errcode.ErrInternal.Wrap(err)
}
- return exportPrivateKey(tw, sk, exportAccountKeyFilename)
-}
+ err = exportPrivateKey(tw, accountPrivateKeyBytes, exportAccountKeyFilename)
+ if err != nil {
+ return errcode.ErrStreamWrite.Wrap(err)
+ }
-func (s *service) exportAccountProofKey(tw *tar.Writer) error {
- sk, err := s.deviceKeystore.AccountProofPrivKey()
+ err = exportPrivateKey(tw, accountProofPrivateKeyBytes, exportAccountProofKeyFilename)
if err != nil {
- return errcode.ErrInternal.Wrap(err)
+ return errcode.ErrStreamWrite.Wrap(err)
}
- return exportPrivateKey(tw, sk, exportAccountProofKeyFilename)
+ return nil
}
func (s *service) exportOrbitDBGroupHeads(gc *GroupContext, headsMetadata []cid.Cid, headsMessages []cid.Cid, tw *tar.Writer) error {
@@ -148,7 +142,7 @@ func (s *service) exportOrbitDBGroupHeads(gc *GroupContext, headsMetadata []cid.
return errcode.ErrSerialization.Wrap(err)
}
- linkKeyArr, err := cryptoutil.GetLinkKeyArray(gc.group)
+ linkKeyArr, err := gc.group.GetLinkKeyArray()
if err != nil {
return errcode.ErrSerialization.Wrap(err)
}
@@ -189,28 +183,23 @@ func (s *service) exportOrbitDBGroupHeads(gc *GroupContext, headsMetadata []cid.
return nil
}
-func exportPrivateKey(tw *tar.Writer, sk crypto.PrivKey, filename string) error {
- skBytes, err := crypto.MarshalPrivateKey(sk)
- if err != nil {
- return errcode.ErrSerialization.Wrap(err)
- }
-
+func exportPrivateKey(tw *tar.Writer, marshalledPrivateKey []byte, filename string) error {
if err := tw.WriteHeader(&tar.Header{
Typeflag: tar.TypeReg,
Name: filename,
Mode: 0o600,
- Size: int64(len(skBytes)),
+ Size: int64(len(marshalledPrivateKey)),
}); err != nil {
return errcode.ErrStreamWrite.Wrap(err)
}
- size, err := tw.Write(skBytes)
+ size, err := tw.Write(marshalledPrivateKey)
if err != nil {
return errcode.ErrStreamWrite.Wrap(err)
}
- if size != len(skBytes) {
- return errcode.ErrStreamWrite.Wrap(fmt.Errorf("wrote %d bytes instead of %d", size, len(skBytes)))
+ if size != len(marshalledPrivateKey) {
+ return errcode.ErrStreamWrite.Wrap(fmt.Errorf("wrote %d bytes instead of %d", size, len(marshalledPrivateKey)))
}
return nil
@@ -250,7 +239,7 @@ func (s *service) exportOrbitDBEntry(ctx context.Context, tw *tar.Writer, idStr
return nil
}
-func readExportSecretKeyFile(expectedSize int64, reader *tar.Reader) (crypto.PrivKey, error) {
+func readExportSecretKeyFile(expectedSize int64, reader *tar.Reader) ([]byte, error) {
if expectedSize == 0 {
return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("invalid expected key size"))
}
@@ -265,16 +254,7 @@ func readExportSecretKeyFile(expectedSize int64, reader *tar.Reader) (crypto.Pri
return nil, errcode.ErrInternal.Wrap(fmt.Errorf("unexpected file size"))
}
- sk, err := crypto.UnmarshalPrivateKey(keyContents.Bytes())
- if err != nil {
- return nil, errcode.ErrDeserialization.Wrap(fmt.Errorf("unable to unmarshal private key"))
- }
-
- if sk.Type() != crypto_pb.KeyType_Ed25519 {
- return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("invalid key format"))
- }
-
- return sk, nil
+ return keyContents.Bytes(), nil
}
func readExportOrbitDBGroupHeads(expectedSize int64, reader *tar.Reader) (*protocoltypes.GroupHeadsExport, []cid.Cid, []cid.Cid, error) {
@@ -354,7 +334,7 @@ type RestoreAccountHandler struct {
}
type restoreAccountState struct {
- keys map[string]crypto.PrivKey
+ keys map[string][]byte
}
func (state *restoreAccountState) readKey(keyName string) RestoreAccountHandler {
@@ -383,7 +363,7 @@ func (state *restoreAccountState) readKey(keyName string) RestoreAccountHandler
func (state *restoreAccountState) restoreKeys(odb *WeshOrbitDB) RestoreAccountHandler {
return RestoreAccountHandler{
PostProcess: func() error {
- if err := odb.deviceKeystore.RestoreAccountKeys(state.keys[exportAccountKeyFilename], state.keys[exportAccountProofKeyFilename]); err != nil {
+ if err := odb.secretStore.ImportAccountKeys(state.keys[exportAccountKeyFilename], state.keys[exportAccountProofKeyFilename]); err != nil {
return errcode.ErrInternal.Wrap(err)
}
@@ -443,7 +423,7 @@ func restoreOrbitDBHeads(ctx context.Context, odb *WeshOrbitDB) RestoreAccountHa
func RestoreAccountExport(ctx context.Context, reader io.Reader, coreAPI ipfs_interface.CoreAPI, odb *WeshOrbitDB, logger *zap.Logger, handlers ...RestoreAccountHandler) error {
tr := tar.NewReader(reader)
state := restoreAccountState{
- keys: map[string]crypto.PrivKey{},
+ keys: map[string][]byte{},
}
handlers = append(
diff --git a/account_export_test.go b/account_export_test.go
index 59459dad..9a22e05b 100644
--- a/account_export_test.go
+++ b/account_export_test.go
@@ -11,21 +11,19 @@ import (
"github.com/ipfs/go-cid"
ds "github.com/ipfs/go-datastore"
dsync "github.com/ipfs/go-datastore/sync"
- "github.com/libp2p/go-libp2p/core/crypto"
mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
"github.com/stretchr/testify/require"
orbitdb "berty.tech/go-orbit-db"
"berty.tech/go-orbit-db/pubsub/pubsubraw"
- "berty.tech/weshnet/internal/datastoreutil"
- "berty.tech/weshnet/pkg/cryptoutil"
"berty.tech/weshnet/pkg/ipfsutil"
"berty.tech/weshnet/pkg/protocoltypes"
+ "berty.tech/weshnet/pkg/secretstore"
"berty.tech/weshnet/pkg/testutil"
"berty.tech/weshnet/pkg/tinder"
)
-func Test_service_exportAccountKey(t *testing.T) {
+func Test_service_exportAccountKeys(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
@@ -53,7 +51,7 @@ func Test_service_exportAccountKey(t *testing.T) {
tw := tar.NewWriter(tmpFile)
- err = s.exportAccountKey(tw)
+ err = s.exportAccountKeys(tw)
require.NoError(t, err)
err = tw.Close()
@@ -63,75 +61,30 @@ func Test_service_exportAccountKey(t *testing.T) {
require.NoError(t, err)
tr := tar.NewReader(tmpFile)
- header, err := tr.Next()
- require.NoError(t, err)
- require.Equal(t, exportAccountKeyFilename, header.Name)
-
- keyContents := make([]byte, header.Size)
-
- size, err := tr.Read(keyContents)
- require.Equal(t, int(header.Size), size)
- sk, err := crypto.UnmarshalPrivateKey(keyContents)
- require.NoError(t, err)
+ accountPrivateKey := getKeyFromTar(t, tr, exportAccountKeyFilename)
+ accountProofPrivateKey := getKeyFromTar(t, tr, exportAccountProofKeyFilename)
- accountSK, err := s.deviceKeystore.AccountPrivKey()
+ inStoreAccountPrivateKeyBytes, inStoreAccountProofPrivateKeyBytes, err := s.secretStore.ExportAccountKeysForBackup()
require.NoError(t, err)
+ require.NotNil(t, inStoreAccountPrivateKeyBytes)
+ require.NotNil(t, inStoreAccountProofPrivateKeyBytes)
- require.True(t, accountSK.Equals(sk))
+ require.Equal(t, accountPrivateKey, inStoreAccountPrivateKeyBytes)
+ require.Equal(t, accountProofPrivateKey, inStoreAccountProofPrivateKeyBytes)
}
-func Test_service_exportAccountProofKey(t *testing.T) {
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- mn := mocknet.New()
- defer mn.Close()
-
- msrv := tinder.NewMockDriverServer()
-
- dsA := dsync.MutexWrap(ds.NewMapDatastore())
- nodeA, closeNodeA := NewTestingProtocol(ctx, t, &TestingOpts{
- Mocknet: mn,
- DiscoveryServer: msrv,
- }, dsA)
- defer closeNodeA()
-
- s, ok := nodeA.Service.(*service)
- require.True(t, ok)
-
- tmpFile, err := ioutil.TempFile(os.TempDir(), "test-export-")
- require.NoError(t, err)
-
- defer os.Remove(tmpFile.Name())
-
- tw := tar.NewWriter(tmpFile)
- err = s.exportAccountProofKey(tw)
- require.NoError(t, err)
-
- err = tw.Close()
- require.NoError(t, err)
-
- _, err = tmpFile.Seek(0, io.SeekStart)
- require.NoError(t, err)
-
- tr := tar.NewReader(tmpFile)
+func getKeyFromTar(t *testing.T, tr *tar.Reader, expectedFilename string) []byte {
header, err := tr.Next()
require.NoError(t, err)
- require.Equal(t, exportAccountProofKeyFilename, header.Name)
+ require.Equal(t, expectedFilename, header.Name)
keyContents := make([]byte, header.Size)
size, err := tr.Read(keyContents)
require.Equal(t, int(header.Size), size)
- sk, err := crypto.UnmarshalPrivateKey(keyContents)
- require.NoError(t, err)
-
- accountProofSK, err := s.deviceKeystore.AccountProofPrivKey()
- require.NoError(t, err)
-
- require.True(t, accountProofSK.Equals(sk))
+ return keyContents
}
func TestRestoreAccount(t *testing.T) {
@@ -215,20 +168,21 @@ func TestRestoreAccount(t *testing.T) {
{
dsB := dsync.MutexWrap(ds.NewMapDatastore())
+ secretStoreB, err := secretstore.NewSecretStore(dsB, nil)
+ require.NoError(t, err)
+
ipfsNodeB := ipfsutil.TestingCoreAPIUsingMockNet(ctx, t, &ipfsutil.TestingAPIOpts{
Mocknet: mn,
Datastore: dsB,
})
- dksB := cryptoutil.NewDeviceKeystore(ipfsutil.NewDatastoreKeystore(datastoreutil.NewNamespacedDatastore(dsB, ds.NewKey(NamespaceDeviceKeystore))), nil)
-
odb, err := NewWeshOrbitDB(ctx, ipfsNodeB.API(), &NewOrbitDBOptions{
NewOrbitDBOptions: orbitdb.NewOrbitDBOptions{
PubSub: pubsubraw.NewPubSub(ipfsNodeB.PubSub(), ipfsNodeB.MockNode().PeerHost.ID(), logger, nil),
Logger: logger,
},
- Datastore: dsB,
- DeviceKeystore: dksB,
+ Datastore: dsB,
+ SecretStore: secretStoreB,
})
require.NoError(t, err)
@@ -238,7 +192,7 @@ func TestRestoreAccount(t *testing.T) {
nodeB, closeNodeB := NewTestingProtocol(ctx, t, &TestingOpts{
Mocknet: mn,
DiscoveryServer: msrv,
- DeviceKeystore: dksB,
+ SecretStore: secretStoreB,
CoreAPIMock: ipfsNodeB,
OrbitDB: odb,
}, dsB)
diff --git a/api/protocol/protocoltypes.proto b/api/protocol/protocoltypes.proto
index 5b313412..4763c9ec 100644
--- a/api/protocol/protocoltypes.proto
+++ b/api/protocol/protocoltypes.proto
@@ -127,20 +127,11 @@ service ProtocolService {
// PeerList returns a list of P2P peers
rpc PeerList(PeerList.Request) returns (PeerList.Reply);
- // PushReceive handles a push payload, decrypts it if possible
- rpc PushReceive(PushReceive.Request) returns (PushReceive.Reply);
+ // OutOfStoreReceive parses a payload received outside a synchronized store
+ rpc OutOfStoreReceive(OutOfStoreReceive.Request) returns (OutOfStoreReceive.Reply);
- // PushSend sends a push payload to a specified list of group members
- rpc PushSend(PushSend.Request) returns (PushSend.Reply);
-
- // PushShareToken sends push tokens of own devices to a group
- rpc PushShareToken(PushShareToken.Request) returns (PushShareToken.Reply);
-
- // PushSetDeviceToken registers a push token for the current device
- rpc PushSetDeviceToken(PushSetDeviceToken.Request) returns (PushSetDeviceToken.Reply);
-
- // PushSetServer registers a push server for the current device
- rpc PushSetServer(PushSetServer.Request) returns (PushSetServer.Reply);
+ // OutOfStoreSeal creates a payload of a message present in store to be sent outside a synchronized store
+ rpc OutOfStoreSeal(OutOfStoreSeal.Request) returns (OutOfStoreSeal.Reply);
// RefreshContactRequest try to refresh the contact request for the given contact
rpc RefreshContactRequest(RefreshContactRequest.Request) returns (RefreshContactRequest.Reply);
@@ -175,8 +166,8 @@ enum EventType {
// EventTypeGroupMemberDeviceAdded indicates the payload includes that a member has added their device to the group
EventTypeGroupMemberDeviceAdded = 1;
- // EventTypeGroupDeviceSecretAdded indicates the payload includes that a member has sent their device secret to another member
- EventTypeGroupDeviceSecretAdded = 2;
+ // EventTypeGroupDeviceChainKeyAdded indicates the payload includes that a member has sent their device chain key to another member
+ EventTypeGroupDeviceChainKeyAdded = 2;
// EventTypeGroupAdditionalRendezvousSeedAdded adds a new rendezvous seed to a group
// Might be implemented later, could be useful for replication services
@@ -285,7 +276,7 @@ message Group {
// secret_sig is the signature of the secret used to ensure the validity of the group
bytes secret_sig = 3;
- // group_type specifies the type of the group, used to determine how device secrets are generated
+ // group_type specifies the type of the group, used to determine how device chain key is generated
GroupType group_type = 4;
// sign_pub is the signature public key used to verify entries, not required when secret and secret_sig are provided
@@ -423,7 +414,7 @@ message ContactAddAliasKey {
}
// GroupAddMemberDevice is an event which indicates to a group a new device (and eventually a new member) is joining it
-// When added on AccountGroup, this event should be followed by appropriate GroupAddMemberDevice and GroupAddDeviceSecret events
+// When added on AccountGroup, this event should be followed by appropriate GroupAddMemberDevice and GroupAddDeviceChainKey events
message GroupAddMemberDevice {
// member_pk is the member sending the event
bytes member_pk = 1 [(gogoproto.customname) = "MemberPK"];
@@ -435,8 +426,8 @@ message GroupAddMemberDevice {
bytes member_sig = 3; // TODO: signature of what ??? ensure it can't be replayed
}
-// DeviceSecret is encrypted for a specific member of the group
-message DeviceSecret {
+// DeviceChainKey is a chain key, which will be encrypted for a specific member of the group
+message DeviceChainKey {
// chain_key is the current value of the chain key of the group device
bytes chain_key = 1;
@@ -444,8 +435,8 @@ message DeviceSecret {
uint64 counter = 2;
}
-// GroupAddDeviceSecret is an event which indicates to a group member a device secret
-message GroupAddDeviceSecret {
+// GroupAddDeviceChainKey is an event which indicates to a group member a device chain key
+message GroupAddDeviceChainKey {
// device_pk is the device sending the event, signs the message
bytes device_pk = 1 [(gogoproto.customname) = "DevicePK"];
@@ -544,7 +535,7 @@ message AccountContactRequestReferenceReset {
// This event should be followed by an AccountGroupJoined event
// This event should be followed by a GroupAddMemberDevice event within the AccountGroup
-// This event should be followed by a GroupAddDeviceSecret event within the AccountGroup
+// This event should be followed by a GroupAddDeviceChainKey event within the AccountGroup
// AccountContactRequestEnqueued indicates that the account will attempt to send a contact request when a matching peer is discovered
message AccountContactRequestEnqueued {
// device_pk is the device sending the event, signs the message
@@ -596,7 +587,7 @@ message AccountContactRequestDiscarded {
}
// This event should be followed by an AccountGroupJoined event
-// This event should be followed by GroupAddMemberDevice and GroupAddDeviceSecret events within the AccountGroup
+// This event should be followed by GroupAddMemberDevice and GroupAddDeviceChainKey events within the AccountGroup
// AccountContactRequestAccepted indicates that a contact request has been accepted
message AccountContactRequestAccepted {
// device_pk is the device sending the event, signs the message
@@ -1436,7 +1427,7 @@ message PushMemberTokenUpdate {
bytes device_pk = 3 [(gogoproto.customname) = "DevicePK"];
}
-message PushReceive {
+message OutOfStoreReceive {
message Request {
bytes payload = 1;
}
@@ -1448,38 +1439,14 @@ message PushReceive {
}
}
-message PushSend {
+message OutOfStoreSeal {
message Request {
bytes cid = 1 [(gogoproto.customname) = "CID"];
bytes group_public_key = 2;
- repeated MemberWithDevices group_members = 3;
}
message Reply {
- repeated MemberWithDevices group_members = 1;
- }
-}
-
-message PushShareToken {
- message Request {
- bytes group_pk = 1 [(gogoproto.customname) = "GroupPK"];
- PushServer server = 2;
- PushServiceReceiver receiver = 3;
+ bytes encrypted = 1;
}
- message Reply {}
-}
-
-message PushSetDeviceToken {
- message Request {
- PushServiceReceiver receiver = 1;
- }
- message Reply {}
-}
-
-message PushSetServer {
- message Request {
- PushServer server = 1;
- }
- message Reply {}
}
message FirstLastCounters {
diff --git a/api/protocol/pushtypes/pushtypes.proto b/api/protocol/pushtypes/pushtypes.proto
index 65d42f7f..3d5e8285 100644
--- a/api/protocol/pushtypes/pushtypes.proto
+++ b/api/protocol/pushtypes/pushtypes.proto
@@ -77,7 +77,7 @@ message OutOfStoreMessageEnvelope {
bytes group_reference = 4 [(gogoproto.customname) = "GroupReference"];
}
-message PushExposedData {
+message OutOfStoreExposedData {
bytes nonce = 1;
bytes box = 2;
}
diff --git a/api_contactrequest.go b/api_contactrequest.go
index 89eed3ad..e6b960d8 100644
--- a/api_contactrequest.go
+++ b/api_contactrequest.go
@@ -133,6 +133,11 @@ func (s *service) ContactRequestAccept(ctx context.Context, req *protocoltypes.C
return nil, errcode.ErrDeserialization.Wrap(err)
}
+ group, err := s.secretStore.GetGroupForContact(pk)
+ if err != nil {
+ return nil, errcode.ErrInternal.Wrap(err)
+ }
+
accountGroup := s.getAccountGroup()
if accountGroup == nil {
return nil, errcode.ErrGroupMissing
@@ -142,7 +147,7 @@ func (s *service) ContactRequestAccept(ctx context.Context, req *protocoltypes.C
return nil, errcode.ErrOrbitDBAppend.Wrap(err)
}
- if err = s.groupDatastore.PutForContactPK(ctx, pk, s.deviceKeystore); err != nil {
+ if err = s.secretStore.PutGroup(ctx, group); err != nil {
return nil, err
}
diff --git a/api_debug.go b/api_debug.go
index 223ee37a..ae002ffb 100644
--- a/api_debug.go
+++ b/api_debug.go
@@ -15,7 +15,6 @@ import (
"berty.tech/go-orbit-db/stores/operation"
"berty.tech/weshnet/internal/sysutil"
- "berty.tech/weshnet/pkg/cryptoutil"
"berty.tech/weshnet/pkg/errcode"
"berty.tech/weshnet/pkg/protocoltypes"
)
@@ -39,19 +38,14 @@ func (s *service) DebugListGroups(req *protocoltypes.DebugListGroups_Request, sr
return errcode.ErrDeserialization.Wrap(err)
}
- sk, err := s.deviceKeystore.ContactGroupPrivKey(pk)
+ group, err := s.secretStore.GetGroupForContact(pk)
if err != nil {
return errcode.ErrCryptoKeyGeneration.Wrap(err)
}
- g, err := cryptoutil.GetGroupForContact(sk)
- if err != nil {
- return errcode.ErrOrbitDBOpen.Wrap(err)
- }
-
if err := srv.SendMsg(&protocoltypes.DebugListGroups_Reply{
- GroupPK: g.PublicKey,
- GroupType: g.GroupType,
+ GroupPK: group.PublicKey,
+ GroupType: group.GroupType,
ContactPK: c.PK,
}); err != nil {
return err
diff --git a/api_group.go b/api_group.go
index e1ee115f..d4fd77be 100644
--- a/api_group.go
+++ b/api_group.go
@@ -47,17 +47,17 @@ func (s *service) GroupInfo(ctx context.Context, req *protocoltypes.GroupInfo_Re
return nil, errcode.ErrInvalidInput
}
- md, err := s.deviceKeystore.MemberDeviceForGroup(g)
+ memberDevice, err := s.secretStore.GetOwnMemberDeviceForGroup(g)
if err != nil {
return nil, errcode.TODO.Wrap(err)
}
- member, err := md.PrivateMember().GetPublic().Raw()
+ member, err := memberDevice.Member().Raw()
if err != nil {
return nil, errcode.ErrSerialization.Wrap(err)
}
- device, err := md.PrivateDevice().GetPublic().Raw()
+ device, err := memberDevice.Device().Raw()
if err != nil {
return nil, errcode.ErrSerialization.Wrap(err)
}
diff --git a/api_multimember.go b/api_multimember.go
index cf5daadd..699fc8de 100644
--- a/api_multimember.go
+++ b/api_multimember.go
@@ -16,7 +16,7 @@ func (s *service) MultiMemberGroupCreate(ctx context.Context, req *protocoltypes
ctx, _, endSection := tyber.Section(ctx, s.logger, "Creating MultiMember group")
defer func() { endSection(err, "") }()
- g, sk, err := NewGroupMultiMember()
+ group, groupPrivateKey, err := NewGroupMultiMember()
if err != nil {
return nil, errcode.ErrCryptoKeyGeneration.Wrap(err)
}
@@ -26,32 +26,32 @@ func (s *service) MultiMemberGroupCreate(ctx context.Context, req *protocoltypes
return nil, errcode.ErrGroupMissing
}
- _, err = accountGroup.MetadataStore().GroupJoin(ctx, g)
+ _, err = accountGroup.MetadataStore().GroupJoin(ctx, group)
if err != nil {
return nil, errcode.ErrOrbitDBAppend.Wrap(err)
}
- if err := s.groupDatastore.Put(ctx, g); err != nil {
+ if err := s.secretStore.PutGroup(ctx, group); err != nil {
return nil, errcode.ErrInternal.Wrap(err)
}
- err = s.activateGroup(ctx, sk.GetPublic(), false)
+ err = s.activateGroup(ctx, groupPrivateKey.GetPublic(), false)
if err != nil {
return nil, errcode.ErrInternal.Wrap(fmt.Errorf("unable to activate group: %w", err))
}
- cg, err := s.GetContextGroupForID(g.PublicKey)
+ cg, err := s.GetContextGroupForID(group.PublicKey)
if err != nil {
return nil, errcode.ErrOrbitDBAppend.Wrap(err)
}
- _, err = cg.MetadataStore().ClaimGroupOwnership(ctx, sk)
+ _, err = cg.MetadataStore().ClaimGroupOwnership(ctx, groupPrivateKey)
if err != nil {
return nil, errcode.ErrOrbitDBAppend.Wrap(err)
}
return &protocoltypes.MultiMemberGroupCreate_Reply{
- GroupPK: g.PublicKey,
+ GroupPK: group.PublicKey,
}, nil
}
diff --git a/api_push.go b/api_push.go
index 144e4f95..83919fde 100644
--- a/api_push.go
+++ b/api_push.go
@@ -1,59 +1,23 @@
package weshnet
import (
- "bytes"
"context"
- crand "crypto/rand"
"crypto/tls"
- "encoding/base64"
- "fmt"
- "sync"
"time"
"github.com/ipfs/go-cid"
- "github.com/libp2p/go-libp2p/core/crypto"
"go.uber.org/zap"
- "golang.org/x/crypto/nacl/box"
"google.golang.org/grpc"
"google.golang.org/grpc/backoff"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
- "berty.tech/weshnet/pkg/cryptoutil"
"berty.tech/weshnet/pkg/errcode"
"berty.tech/weshnet/pkg/logutil"
"berty.tech/weshnet/pkg/protocoltypes"
"berty.tech/weshnet/pkg/pushtypes"
)
-func PushSealTokenForServer(receiver *protocoltypes.PushServiceReceiver, server *protocoltypes.PushServer) (*protocoltypes.PushMemberTokenUpdate, error) {
- if server == nil || len(server.ServerKey) != cryptoutil.KeySize {
- return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("expected a server key of %d bytes", cryptoutil.KeySize))
- }
-
- if receiver == nil {
- return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("expected the receiver value to be defined"))
- }
-
- serverKey := [cryptoutil.KeySize]byte{}
- copy(serverKey[:], server.ServerKey)
-
- opaqueToken, err := receiver.Marshal()
- if err != nil {
- return nil, errcode.ErrSerialization.Wrap(err)
- }
-
- opaqueToken, err = box.SealAnonymous(nil, opaqueToken, &serverKey, crand.Reader)
- if err != nil {
- return nil, err
- }
-
- return &protocoltypes.PushMemberTokenUpdate{
- Token: opaqueToken,
- Server: server,
- }, nil
-}
-
func (s *service) getPushClient(host string) (pushtypes.PushServiceClient, error) {
s.muPushClients.Lock()
defer s.muPushClients.Unlock()
@@ -95,11 +59,21 @@ func (s *service) getPushClient(host string) (pushtypes.PushServiceClient, error
return pushtypes.NewPushServiceClient(cc), err
}
-func (s *service) PushReceive(ctx context.Context, request *protocoltypes.PushReceive_Request) (*protocoltypes.PushReceive_Reply, error) {
- return s.pushHandler.PushReceive(ctx, request.Payload)
+func (s *service) OutOfStoreReceive(ctx context.Context, request *protocoltypes.OutOfStoreReceive_Request) (*protocoltypes.OutOfStoreReceive_Reply, error) {
+ outOfStoreMessage, group, clearPayload, alreadyDecrypted, err := s.secretStore.OpenOutOfStoreMessage(ctx, request.Payload)
+ if err != nil {
+ return nil, errcode.ErrCryptoDecrypt.Wrap(err)
+ }
+
+ return &protocoltypes.OutOfStoreReceive_Reply{
+ Message: outOfStoreMessage,
+ Cleartext: clearPayload,
+ GroupPublicKey: group.PublicKey,
+ AlreadyReceived: alreadyDecrypted,
+ }, nil
}
-func (s *service) PushSend(ctx context.Context, request *protocoltypes.PushSend_Request) (*protocoltypes.PushSend_Reply, error) {
+func (s *service) OutOfStoreSeal(ctx context.Context, request *protocoltypes.OutOfStoreSeal_Request) (*protocoltypes.OutOfStoreSeal_Reply, error) {
gc, err := s.GetContextGroupForID(request.GroupPublicKey)
if err != nil {
return nil, err
@@ -115,193 +89,14 @@ func (s *service) PushSend(ctx context.Context, request *protocoltypes.PushSend_
return nil, errcode.ErrInternal.Wrap(err)
}
- pushTargets, err := s.getPushTargetsByServer(gc, request.GroupMembers)
- if err != nil {
- return nil, errcode.ErrInternal.Wrap(err)
- }
-
- if len(pushTargets) == 0 {
- s.logger.Info("PushSend - pushing - no targets", logutil.PrivateString("cid", c.String()))
- return &protocoltypes.PushSend_Reply{}, nil
- }
-
- wg := sync.WaitGroup{}
- wg.Add(len(pushTargets))
-
- for serverAddr, pushTokens := range pushTargets {
- // @FIXME(gfanton): find a better way to get service token
- go func(serverAddr string, pushTokens []*pushtypes.PushServiceOpaqueReceiver) {
- s.logger.Info("PushSend - pushing", logutil.PrivateString("cid", c.String()), logutil.PrivateString("server", serverAddr))
- defer wg.Done()
-
- if len(pushTokens) == 0 {
- s.logger.Info("no push receivers", logutil.PrivateString("push-server", serverAddr))
- return
- }
-
- client, err := s.getPushClient(serverAddr)
- if err != nil {
- s.logger.Error("error while dialing push server", logutil.PrivateString("push-server", serverAddr), zap.Error(err))
- return
- }
-
- _, err = client.Send(ctx, &pushtypes.PushServiceSend_Request{
- Envelope: sealedMessageEnvelope,
- Priority: pushtypes.PushServicePriority_PushPriorityNormal,
- Receivers: pushTokens,
- }, grpc.WaitForReady(true))
- if err != nil {
- s.logger.Error("error while dialing push server", logutil.PrivateString("push-server", serverAddr), zap.Error(err))
- return
- }
-
- s.logger.Debug("send push notification successfully", logutil.PrivateString("cid", c.String()), logutil.PrivateString("endpoint", serverAddr))
- }(serverAddr, pushTokens)
- }
-
- wg.Wait()
-
- return &protocoltypes.PushSend_Reply{}, nil
-}
-
-func (s *service) getPushTargetsByServer(gc *GroupContext, targetGroupMembers []*protocoltypes.MemberWithDevices) (map[string][]*pushtypes.PushServiceOpaqueReceiver, error) {
- pushTargets := []*protocoltypes.PushMemberTokenUpdate(nil)
- serverTokens := map[string][]*pushtypes.PushServiceOpaqueReceiver{}
- targetDevices := []crypto.PubKey(nil)
-
- if len(targetGroupMembers) == 0 {
- targetDevices = gc.metadataStore.ListOtherMembersDevices()
- } else {
- for _, memberAndDevices := range targetGroupMembers {
- pk, err := crypto.UnmarshalEd25519PublicKey(memberAndDevices.MemberPK)
- if err != nil {
- return nil, errcode.ErrDeserialization.Wrap(err)
- }
-
- if len(memberAndDevices.DevicePKs) == 0 {
- // If no devices provided push all devices
- devices, err := gc.metadataStore.GetDevicesForMember(pk)
- if err != nil {
- return nil, errcode.ErrInternal.Wrap(err)
- }
-
- targetDevices = append(targetDevices, devices...)
- continue
- }
-
- for _, pkB := range memberAndDevices.DevicePKs {
- devPK, err := crypto.UnmarshalEd25519PublicKey(pkB)
- if err != nil {
- return nil, errcode.ErrDeserialization.Wrap(err)
- }
-
- member, err := gc.metadataStore.GetMemberByDevice(devPK)
- if err != nil {
- s.logger.Warn("error while retrieving member for device", zap.Error(err))
- continue
- }
-
- if !member.Equals(devPK) {
- s.logger.Warn("device does not belong to member")
- continue
- }
-
- targetDevices = append(targetDevices, devPK)
- }
- }
- }
-
- for _, d := range targetDevices {
- pushToken, err := gc.metadataStore.GetPushTokenForDevice(d)
- if err != nil {
- s.logger.Info("unable to get push token for device")
- continue
- }
-
- pushTargets = append(pushTargets, pushToken)
- }
-
- for _, pushTarget := range pushTargets {
- serverTokens[pushTarget.Server.ServiceAddr] = append(serverTokens[pushTarget.Server.ServiceAddr], &pushtypes.PushServiceOpaqueReceiver{OpaqueToken: pushTarget.Token})
- }
-
- return serverTokens, nil
-}
-
-func (s *service) PushShareToken(ctx context.Context, request *protocoltypes.PushShareToken_Request) (*protocoltypes.PushShareToken_Reply, error) {
- gc, err := s.GetContextGroupForID(request.GroupPK)
- if err != nil {
- return nil, errcode.ErrInvalidInput.Wrap(err)
- }
-
- token, err := PushSealTokenForServer(request.Receiver, request.Server)
+ sealedMessageEnvelopeBytes, err := sealedMessageEnvelope.Marshal()
if err != nil {
- return nil, errcode.ErrInternal.Wrap(err)
- }
-
- if _, err := gc.metadataStore.SendPushToken(ctx, token); err != nil {
- return nil, err
- }
- s.logger.Debug("send push token done")
-
- return &protocoltypes.PushShareToken_Reply{}, nil
-}
-
-func (s *service) PushSetDeviceToken(ctx context.Context, request *protocoltypes.PushSetDeviceToken_Request) (*protocoltypes.PushSetDeviceToken_Reply, error) {
- s.lock.Lock()
- defer s.lock.Unlock()
-
- if request.Receiver == nil || request.Receiver.TokenType == pushtypes.PushServiceTokenType_PushTokenUndefined {
- return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("invalid push token provided"))
- }
-
- request.Receiver.RecipientPublicKey = s.pushHandler.PushPK()[:]
-
- if s.accountGroup == nil {
- return nil, errcode.ErrGroupActivate.Wrap(fmt.Errorf("accountGroup is deactivated"))
- }
-
- if currentReceiver := s.accountGroup.metadataStore.getCurrentDevicePushToken(); currentReceiver != nil && bytes.Equal(currentReceiver.Token, request.Receiver.Token) {
- s.logger.Warn("push device token already set", logutil.PrivateString("b64 token", base64.StdEncoding.EncodeToString(request.Receiver.Token)))
- return &protocoltypes.PushSetDeviceToken_Reply{}, nil
- }
-
- if _, err := s.accountGroup.metadataStore.RegisterDevicePushToken(ctx, request.Receiver); err != nil {
- return nil, errcode.ErrInternal.Wrap(err)
- }
-
- s.logger.Debug("push token device set", zap.Int("token len", len(request.Receiver.Token)))
-
- return &protocoltypes.PushSetDeviceToken_Reply{}, nil
-}
-
-func (s *service) PushSetServer(ctx context.Context, request *protocoltypes.PushSetServer_Request) (*protocoltypes.PushSetServer_Reply, error) {
- s.lock.Lock()
- defer s.lock.Unlock()
-
- if request.Server == nil {
- return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("no push server provided"))
- }
-
- if s.accountGroup == nil {
- return nil, errcode.ErrGroupActivate.Wrap(fmt.Errorf("accountGroup is deactivated"))
- }
-
- if currentServer := s.accountGroup.metadataStore.getCurrentDevicePushServer(); currentServer != nil &&
- bytes.Equal(currentServer.ServerKey, request.Server.ServerKey) &&
- currentServer.ServiceAddr == request.Server.ServiceAddr {
- return &protocoltypes.PushSetServer_Reply{}, nil
- }
-
- if _, err := s.accountGroup.metadataStore.RegisterDevicePushServer(ctx, request.Server); err != nil {
- return nil, errcode.ErrInternal.Wrap(err)
- }
-
- if err := s.pushHandler.UpdatePushServer(ctx, request.Server); err != nil {
- return nil, errcode.ErrInternal.Wrap(err)
+ return nil, errcode.ErrSerialization.Wrap(err)
}
- return &protocoltypes.PushSetServer_Reply{}, nil
+ return &protocoltypes.OutOfStoreSeal_Reply{
+ Encrypted: sealedMessageEnvelopeBytes,
+ }, nil
}
func (s *service) GetCurrentDevicePushConfig() (*protocoltypes.PushServiceReceiver, *protocoltypes.PushServer) {
diff --git a/api_push_test.go b/api_push_test.go
deleted file mode 100644
index 4a09f32e..00000000
--- a/api_push_test.go
+++ /dev/null
@@ -1,246 +0,0 @@
-package weshnet_test
-
-import (
- "context"
- crand "crypto/rand"
- "testing"
-
- "github.com/ipfs/go-cid"
- "github.com/stretchr/testify/require"
- "golang.org/x/crypto/nacl/box"
-
- weshnet "berty.tech/weshnet"
- "berty.tech/weshnet/pkg/bertypush"
- "berty.tech/weshnet/pkg/cryptoutil"
- "berty.tech/weshnet/pkg/protocoltypes"
- "berty.tech/weshnet/pkg/pushtypes"
-)
-
-func Test_sealPushMessage_decryptOutOfStoreMessageEnv(t *testing.T) {
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- _, devicePushSK, err := box.GenerateKey(crand.Reader)
- require.NoError(t, err)
-
- tp, cancel := weshnet.NewTestingProtocol(ctx, t, &weshnet.TestingOpts{PushSK: devicePushSK}, nil)
- defer cancel()
-
- g, _, err := weshnet.NewGroupMultiMember()
- require.NoError(t, err)
-
- s := tp.Service
-
- gPK, err := g.GetPubKey()
- require.NoError(t, err)
-
- _, err = s.MultiMemberGroupJoin(ctx, &protocoltypes.MultiMemberGroupJoin_Request{Group: g})
- require.NoError(t, err)
-
- gPKRaw, err := gPK.Raw()
- require.NoError(t, err)
-
- _, err = s.ActivateGroup(ctx, &protocoltypes.ActivateGroup_Request{GroupPK: gPKRaw})
- require.NoError(t, err)
-
- gc, err := s.(weshnet.ServiceMethods).GetContextGroupForID(g.PublicKey)
- require.NoError(t, err)
-
- otherMD, otherDS := weshnet.CreateVirtualOtherPeerSecretsShareSecret(t, ctx, []*weshnet.MetadataStore{gc.MetadataStore()})
-
- testPayload := []byte("test payload")
-
- envBytes, err := cryptoutil.SealEnvelope(testPayload, otherDS, otherMD.PrivateDevice(), g)
- require.NoError(t, err)
-
- env, headers, err := cryptoutil.OpenEnvelopeHeaders(envBytes, g)
- require.NoError(t, err)
-
- oosMsgEnv, err := weshnet.SealOutOfStoreMessageEnvelope(cid.Undef, env, headers, g)
- require.NoError(t, err)
-
- openedOOSMessage, err := bertypush.DecryptOutOfStoreMessageEnv(ctx, tp.GroupDatastore, oosMsgEnv, gPK)
- require.NoError(t, err)
-
- require.Equal(t, headers.Counter, openedOOSMessage.Counter)
- require.Equal(t, headers.DevicePK, openedOOSMessage.DevicePK)
- require.Equal(t, headers.Sig, openedOOSMessage.Sig)
- require.Equal(t, env.Message, openedOOSMessage.EncryptedPayload)
-}
-
-func TestService_PushShareToken(t *testing.T) {
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- devicePushPK, devicePushSK, err := box.GenerateKey(crand.Reader)
- require.NoError(t, err)
-
- serverPushPK, _, err := box.GenerateKey(crand.Reader)
- require.NoError(t, err)
-
- tokenTestData := []byte("token_test_data_1")
- const nameTestPackage = "test.app"
- const serverAddr1 = "server1.test"
-
- tp, cancel := weshnet.NewTestingProtocol(ctx, t, &weshnet.TestingOpts{PushSK: devicePushSK}, nil)
- defer cancel()
-
- s := tp.Service
-
- _, err = s.PushSetServer(ctx, &protocoltypes.PushSetServer_Request{Server: &protocoltypes.PushServer{
- ServerKey: serverPushPK[:],
- ServiceAddr: serverAddr1,
- }})
- require.NoError(t, err)
-
- _, err = s.PushSetDeviceToken(ctx, &protocoltypes.PushSetDeviceToken_Request{
- Receiver: &protocoltypes.PushServiceReceiver{
- TokenType: pushtypes.PushServiceTokenType_PushTokenApplePushNotificationService,
- BundleID: nameTestPackage,
- Token: tokenTestData,
- RecipientPublicKey: devicePushPK[:],
- },
- })
- require.NoError(t, err)
-
- g, gSK, err := weshnet.NewGroupMultiMember()
- require.NoError(t, err)
-
- _, err = s.MultiMemberGroupJoin(ctx, &protocoltypes.MultiMemberGroupJoin_Request{Group: g})
- require.NoError(t, err)
-
- gPK, _ := gSK.GetPublic().Raw()
- require.NoError(t, err)
-
- _, err = s.ActivateGroup(ctx, &protocoltypes.ActivateGroup_Request{GroupPK: gPK})
- require.NoError(t, err)
-
- gc, err := s.(weshnet.ServiceMethods).GetContextGroupForID(g.PublicKey)
- require.NoError(t, err)
-
- pushToken, err := gc.MetadataStore().GetPushTokenForDevice(gc.DevicePubKey())
- require.Error(t, err)
- require.Nil(t, pushToken)
-
- _, err = s.PushShareToken(ctx, &protocoltypes.PushShareToken_Request{
- GroupPK: g.PublicKey,
- Server: &protocoltypes.PushServer{
- ServerKey: serverPushPK[:],
- ServiceAddr: serverAddr1,
- },
- Receiver: &protocoltypes.PushServiceReceiver{
- TokenType: pushtypes.PushServiceTokenType_PushTokenApplePushNotificationService,
- BundleID: nameTestPackage,
- Token: tokenTestData,
- RecipientPublicKey: devicePushPK[:],
- },
- })
- require.NoError(t, err)
-
- pushToken, err = gc.MetadataStore().GetPushTokenForDevice(gc.DevicePubKey())
- require.NoError(t, err)
- require.NotNil(t, pushToken)
- require.Equal(t, serverAddr1, pushToken.Server.ServiceAddr)
- require.Equal(t, serverPushPK[:], pushToken.Server.ServerKey)
-}
-
-func TestService_PushSetDeviceToken(t *testing.T) {
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- devicePushPK, devicePushSK, err := box.GenerateKey(crand.Reader)
- require.NoError(t, err)
-
- tokenTestData1 := []byte("token_test_data_1")
- tokenTestData2 := []byte("token_test_data_2")
- const nameTestPackage = "test.app"
-
- tp, cancel := weshnet.NewTestingProtocol(ctx, t, &weshnet.TestingOpts{PushSK: devicePushSK}, nil)
- defer cancel()
-
- s := tp.Service
-
- currentPush, _ := s.(weshnet.ServiceMethods).GetCurrentDevicePushConfig()
- require.Nil(t, currentPush)
-
- _, err = s.PushSetDeviceToken(ctx, &protocoltypes.PushSetDeviceToken_Request{
- Receiver: &protocoltypes.PushServiceReceiver{
- TokenType: pushtypes.PushServiceTokenType_PushTokenMQTT,
- BundleID: nameTestPackage,
- Token: tokenTestData1,
- },
- })
- require.NoError(t, err)
-
- currentPush, _ = s.(weshnet.ServiceMethods).GetCurrentDevicePushConfig()
- require.NotNil(t, currentPush)
- require.Equal(t, tokenTestData1, currentPush.Token)
- require.Equal(t, nameTestPackage, currentPush.BundleID)
- require.Equal(t, pushtypes.PushServiceTokenType_PushTokenMQTT, currentPush.TokenType)
- require.Equal(t, devicePushPK[:], currentPush.RecipientPublicKey)
-
- _, err = s.PushSetDeviceToken(ctx, &protocoltypes.PushSetDeviceToken_Request{
- Receiver: &protocoltypes.PushServiceReceiver{
- TokenType: pushtypes.PushServiceTokenType_PushTokenApplePushNotificationService,
- BundleID: nameTestPackage,
- Token: tokenTestData2,
- },
- })
- require.NoError(t, err)
-
- currentPush, _ = s.(weshnet.ServiceMethods).GetCurrentDevicePushConfig()
- require.NotNil(t, currentPush)
- require.Equal(t, tokenTestData2, currentPush.Token)
- require.Equal(t, nameTestPackage, currentPush.BundleID)
- require.Equal(t, pushtypes.PushServiceTokenType_PushTokenApplePushNotificationService, currentPush.TokenType)
- require.Equal(t, devicePushPK[:], currentPush.RecipientPublicKey)
-}
-
-func TestService_PushSetServer(t *testing.T) {
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- const serverAddr1 = "server1.test"
- const serverAddr2 = "server2.test"
-
- _, devicePushSK, err := box.GenerateKey(crand.Reader)
- require.NoError(t, err)
-
- serverPushPK1, _, err := box.GenerateKey(crand.Reader)
- require.NoError(t, err)
-
- serverPushPK2, _, err := box.GenerateKey(crand.Reader)
- require.NoError(t, err)
-
- tp, cancel := weshnet.NewTestingProtocol(ctx, t, &weshnet.TestingOpts{PushSK: devicePushSK}, nil)
- defer cancel()
-
- s := tp.Service
-
- _, currentPush := s.(weshnet.ServiceMethods).GetCurrentDevicePushConfig()
- require.Nil(t, currentPush)
-
- _, err = s.PushSetServer(ctx, &protocoltypes.PushSetServer_Request{Server: &protocoltypes.PushServer{
- ServerKey: serverPushPK1[:],
- ServiceAddr: serverAddr1,
- }})
- require.NoError(t, err)
-
- _, currentPush = s.(weshnet.ServiceMethods).GetCurrentDevicePushConfig()
- require.NotNil(t, currentPush)
- require.Equal(t, serverPushPK1[:], currentPush.ServerKey)
- require.Equal(t, serverAddr1, currentPush.ServiceAddr)
-
- _, err = s.PushSetServer(ctx, &protocoltypes.PushSetServer_Request{Server: &protocoltypes.PushServer{
- ServerKey: serverPushPK2[:],
- ServiceAddr: serverAddr2,
- }})
- require.NoError(t, err)
-
- _, currentPush = s.(weshnet.ServiceMethods).GetCurrentDevicePushConfig()
- require.NotNil(t, currentPush)
- require.Equal(t, serverPushPK2[:], currentPush.ServerKey)
- require.Equal(t, serverAddr2, currentPush.ServiceAddr)
-
- // FIXME: Should we add a way to clear the push server used with the current device?
-}
diff --git a/api_replication.go b/api_replication.go
index 45776113..b2cf0741 100644
--- a/api_replication.go
+++ b/api_replication.go
@@ -12,7 +12,6 @@ import (
"google.golang.org/grpc/credentials/insecure"
"berty.tech/weshnet/pkg/authtypes"
- "berty.tech/weshnet/pkg/cryptoutil"
"berty.tech/weshnet/pkg/errcode"
"berty.tech/weshnet/pkg/grpcutil"
"berty.tech/weshnet/pkg/logutil"
@@ -32,7 +31,7 @@ func FilterGroupForReplication(m *protocoltypes.Group) (*protocoltypes.Group, er
return nil, errcode.ErrSerialization.Wrap(err)
}
- linkKey, err := cryptoutil.GetLinkKeyArray(m)
+ linkKey, err := m.GetLinkKeyArray()
if err != nil {
return nil, errcode.TODO.Wrap(err)
}
diff --git a/api_services_auth.go b/api_services_auth.go
index 03fb4e28..2888f9a5 100644
--- a/api_services_auth.go
+++ b/api_services_auth.go
@@ -163,7 +163,7 @@ func (s *service) AuthServiceCompleteFlow(ctx context.Context, request *protocol
}
// @FIXME(gfanton): should be handle on the client (js) side
- registeredPushServer := 0
+ // registeredPushServer := 0
for _, service := range services {
if service.ServiceType != authtypes.ServicePushID {
continue
@@ -185,25 +185,25 @@ func (s *service) AuthServiceCompleteFlow(ctx context.Context, request *protocol
continue
}
- _, err = s.PushSetServer(ctx, &protocoltypes.PushSetServer_Request{
- Server: &protocoltypes.PushServer{
- ServerKey: repl.PublicKey,
- ServiceAddr: service.ServiceEndpoint,
- },
- })
-
- if err != nil {
- s.logger.Warn("unable to set push server", zap.Error(err))
- continue
- }
-
- registeredPushServer++
- s.logger.Debug("push server registered", logutil.PrivateString("endpoint", service.GetServiceEndpoint()))
+ // _, err = s.PushSetServer(ctx, &protocoltypes.PushSetServer_Request{
+ // Server: &protocoltypes.PushServer{
+ // ServerKey: repl.PublicKey,
+ // ServiceAddr: service.ServiceEndpoint,
+ // },
+ // })
+
+ // if err != nil {
+ // s.logger.Warn("unable to set push server", zap.Error(err))
+ // continue
+ // }
+ //
+ // registeredPushServer++
+ // s.logger.Debug("push server registered", logutil.PrivateString("endpoint", service.GetServiceEndpoint()))
}
- if registeredPushServer == 0 {
- s.logger.Warn("no push server found/registered")
- }
+ // if registeredPushServer == 0 {
+ // s.logger.Warn("no push server found/registered")
+ // }
return &protocoltypes.AuthServiceCompleteFlow_Reply{
TokenID: svcToken.TokenID(),
diff --git a/api_verified_credentials.go b/api_verified_credentials.go
index e7b6164c..56f8110d 100644
--- a/api_verified_credentials.go
+++ b/api_verified_credentials.go
@@ -3,31 +3,16 @@ package weshnet
import (
"bytes"
"context"
- stdcrypto "crypto"
"fmt"
- "io"
"strings"
"time"
- libp2p_ci "github.com/libp2p/go-libp2p/core/crypto"
-
"berty.tech/weshnet/pkg/bertyvcissuer"
+ "berty.tech/weshnet/pkg/cryptoutil"
"berty.tech/weshnet/pkg/errcode"
"berty.tech/weshnet/pkg/protocoltypes"
)
-type signerWrapper struct {
- libp2p_ci.PrivKey
-}
-
-func (s *signerWrapper) Public() stdcrypto.PublicKey {
- return s.PrivKey.GetPublic()
-}
-
-func (s *signerWrapper) Sign(_ io.Reader, digest []byte, _ stdcrypto.SignerOpts) (signature []byte, err error) {
- return s.PrivKey.Sign(digest)
-}
-
func (s *service) CredentialVerificationServiceInitFlow(ctx context.Context, request *protocoltypes.CredentialVerificationServiceInitFlow_Request) (*protocoltypes.CredentialVerificationServiceInitFlow_Reply, error) {
s.lock.Lock()
s.vcClient = bertyvcissuer.NewClient(request.ServiceURL)
@@ -38,12 +23,8 @@ func (s *service) CredentialVerificationServiceInitFlow(ctx context.Context, req
defer cancel()
// TODO: allow selection of alt-scoped keys
- sk, err := s.deviceKeystore.AccountPrivKey()
- if err != nil {
- return nil, errcode.ErrInvalidInput
- }
-
- pkRaw, err := sk.GetPublic().Raw()
+ // TODO: avoid exporting account keys
+ pkRaw, err := s.accountGroupCtx.ownMemberDevice.Member().Raw()
if err != nil {
return nil, errcode.ErrInvalidInput
}
@@ -52,7 +33,7 @@ func (s *service) CredentialVerificationServiceInitFlow(ctx context.Context, req
return nil, errcode.ErrInvalidInput
}
- url, err := client.Init(ctx, request.Link, &signerWrapper{sk})
+ url, err := client.Init(ctx, request.Link, cryptoutil.NewFuncSigner(s.accountGroupCtx.ownMemberDevice.Member(), s.accountGroupCtx.ownMemberDevice.MemberSign))
if err != nil {
return nil, errcode.ErrInternal.Wrap(err)
}
@@ -77,7 +58,7 @@ func (s *service) CredentialVerificationServiceCompleteFlow(ctx context.Context,
return nil, errcode.ErrInternal.Wrap(err)
}
- _, err = s.accountGroup.metadataStore.SendAccountVerifiedCredentialAdded(ctx, &protocoltypes.AccountVerifiedCredentialRegistered{
+ _, err = s.accountGroupCtx.metadataStore.SendAccountVerifiedCredentialAdded(ctx, &protocoltypes.AccountVerifiedCredentialRegistered{
VerifiedCredential: credentials,
RegistrationDate: parsedCredential.Issued.UnixNano(),
ExpirationDate: parsedCredential.Expired.UnixNano(),
@@ -95,7 +76,7 @@ func (s *service) CredentialVerificationServiceCompleteFlow(ctx context.Context,
func (s *service) VerifiedCredentialsList(request *protocoltypes.VerifiedCredentialsList_Request, server protocoltypes.ProtocolService_VerifiedCredentialsListServer) error {
now := time.Now().UnixNano()
- credentials := s.accountGroup.metadataStore.ListVerifiedCredentials()
+ credentials := s.accountGroupCtx.metadataStore.ListVerifiedCredentials()
for _, credential := range credentials {
if request.FilterIdentifier != "" && credential.Identifier != request.FilterIdentifier {
diff --git a/blackbox_test.go b/blackbox_test.go
index 19c6d4ad..9857572b 100644
--- a/blackbox_test.go
+++ b/blackbox_test.go
@@ -7,12 +7,12 @@ import (
"os"
"testing"
- keystore "github.com/ipfs/go-ipfs-keystore"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
"berty.tech/weshnet"
- "berty.tech/weshnet/pkg/cryptoutil"
"berty.tech/weshnet/pkg/protocoltypes"
+ "berty.tech/weshnet/pkg/secretstore"
"berty.tech/weshnet/pkg/testutil"
)
@@ -23,9 +23,12 @@ func TestTestingClient_impl(t *testing.T) {
logger, cleanup := testutil.Logger(t)
defer cleanup()
+ secretStore, err := secretstore.NewInMemSecretStore(nil)
+ require.NoError(t, err)
+
client, cleanup := weshnet.TestingService(ctx, t, weshnet.Opts{
- Logger: logger,
- DeviceKeystore: cryptoutil.NewDeviceKeystore(keystore.NewMemKeystore(), nil),
+ Logger: logger,
+ SecretStore: secretStore,
})
defer cleanup()
diff --git a/consts.go b/consts.go
index c0742f23..386e48e2 100644
--- a/consts.go
+++ b/consts.go
@@ -5,7 +5,6 @@ import (
)
const (
- NamespaceDeviceKeystore = "device_keystore"
NamespaceOrbitDBDatastore = "orbitdb_datastore"
NamespaceOrbitDBDirectory = "orbitdb"
NamespaceIPFSDatastore = "ipfs_datastore"
diff --git a/contact_request_manager.go b/contact_request_manager.go
index 47bc9637..4871e86b 100644
--- a/contact_request_manager.go
+++ b/contact_request_manager.go
@@ -42,7 +42,7 @@ type contactRequestsManager struct {
enabled bool
ownRendezvousSeed []byte
- accSK crypto.PrivKey
+ accountPrivateKey crypto.PrivKey
ipfs ipfsutil.ExtendedCoreAPI
swiper *Swiper
@@ -50,7 +50,7 @@ type contactRequestsManager struct {
}
func newContactRequestsManager(s *Swiper, store *MetadataStore, ipfs ipfsutil.ExtendedCoreAPI, logger *zap.Logger) (*contactRequestsManager, error) {
- sk, err := store.devKS.AccountPrivKey()
+ accountPrivateKey, err := store.secretStore.GetAccountPrivateKey()
if err != nil {
return nil, err
}
@@ -58,14 +58,14 @@ func newContactRequestsManager(s *Swiper, store *MetadataStore, ipfs ipfsutil.Ex
ctx, cancel := context.WithCancel(context.Background())
cm := &contactRequestsManager{
- lookupProcess: make(map[string]context.CancelFunc),
- metadataStore: store,
- ipfs: ipfs,
- logger: logger.Named("req-mngr"),
- accSK: sk,
- ctx: ctx,
- cancel: cancel,
- swiper: s,
+ lookupProcess: make(map[string]context.CancelFunc),
+ metadataStore: store,
+ ipfs: ipfs,
+ logger: logger.Named("req-mngr"),
+ accountPrivateKey: accountPrivateKey,
+ ctx: ctx,
+ cancel: cancel,
+ swiper: s,
}
go cm.metadataWatcher(ctx)
@@ -199,7 +199,7 @@ func (c *contactRequestsManager) enableContactRequest(ctx context.Context) error
return nil
}
- pkBytes, err := c.accSK.GetPublic().Raw()
+ pkBytes, err := c.accountPrivateKey.GetPublic().Raw()
if err != nil {
return fmt.Errorf("unable to get raw pk: %w", err)
}
@@ -236,7 +236,7 @@ func (c *contactRequestsManager) metadataRequestReset(ctx context.Context, evt *
return errcode.ErrDeserialization.Wrap(err)
}
- accPK, err := c.accSK.GetPublic().Raw()
+ accPK, err := c.accountPrivateKey.GetPublic().Raw()
if err != nil {
return fmt.Errorf("unable to get raw pk: %w", err)
}
@@ -452,7 +452,7 @@ func (c *contactRequestsManager) SendContactRequest(ctx context.Context, to *pro
c.logger.Debug("performing handshake")
tyber.LogStep(ctx, c.logger, "performing handshake")
- if err := handshake.RequestUsingReaderWriter(ctx, c.logger, reader, writer, c.accSK, otherPK); err != nil {
+ if err := handshake.RequestUsingReaderWriter(ctx, c.logger, reader, writer, c.accountPrivateKey, otherPK); err != nil {
return fmt.Errorf("an error occurred during handshake: %w", err)
}
@@ -463,7 +463,7 @@ func (c *contactRequestsManager) SendContactRequest(ctx context.Context, to *pro
}
tyber.LogStep(ctx, c.logger, "mark contact request has sent")
- // mark this contact request has send
+ // mark this contact request as sent
if _, err := c.metadataStore.ContactRequestOutgoingSent(ctx, otherPK); err != nil {
return fmt.Errorf("an error occurred while marking contact request as sent: %w", err)
}
@@ -477,7 +477,7 @@ func (c *contactRequestsManager) handleIncomingRequest(ctx context.Context, stre
tyber.LogStep(ctx, c.logger, "responding to handshake")
- otherPK, err := handshake.ResponseUsingReaderWriter(ctx, c.logger, reader, writer, c.accSK)
+ otherPK, err := handshake.ResponseUsingReaderWriter(ctx, c.logger, reader, writer, c.accountPrivateKey)
if err != nil {
return fmt.Errorf("handshake failed: %w", err)
}
diff --git a/docs/apis/protocoltypes.md b/docs/apis/protocoltypes.md
index 1702f364..48ba97ac 100644
--- a/docs/apis/protocoltypes.md
+++ b/docs/apis/protocoltypes.md
@@ -90,13 +90,13 @@
- [DebugListGroups](#weshnet-protocol-v1-DebugListGroups)
- [DebugListGroups.Reply](#weshnet-protocol-v1-DebugListGroups-Reply)
- [DebugListGroups.Request](#weshnet-protocol-v1-DebugListGroups-Request)
- - [DeviceSecret](#weshnet-protocol-v1-DeviceSecret)
+ - [DeviceChainKey](#weshnet-protocol-v1-DeviceChainKey)
- [EncryptedMessage](#weshnet-protocol-v1-EncryptedMessage)
- [EventContext](#weshnet-protocol-v1-EventContext)
- [FirstLastCounters](#weshnet-protocol-v1-FirstLastCounters)
- [Group](#weshnet-protocol-v1-Group)
- [GroupAddAdditionalRendezvousSeed](#weshnet-protocol-v1-GroupAddAdditionalRendezvousSeed)
- - [GroupAddDeviceSecret](#weshnet-protocol-v1-GroupAddDeviceSecret)
+ - [GroupAddDeviceChainKey](#weshnet-protocol-v1-GroupAddDeviceChainKey)
- [GroupAddMemberDevice](#weshnet-protocol-v1-GroupAddMemberDevice)
- [GroupDeviceStatus](#weshnet-protocol-v1-GroupDeviceStatus)
- [GroupDeviceStatus.Reply](#weshnet-protocol-v1-GroupDeviceStatus-Reply)
@@ -146,6 +146,12 @@
- [OrbitDBMessageHeads](#weshnet-protocol-v1-OrbitDBMessageHeads)
- [OrbitDBMessageHeads.Box](#weshnet-protocol-v1-OrbitDBMessageHeads-Box)
- [OutOfStoreMessage](#weshnet-protocol-v1-OutOfStoreMessage)
+ - [OutOfStoreReceive](#weshnet-protocol-v1-OutOfStoreReceive)
+ - [OutOfStoreReceive.Reply](#weshnet-protocol-v1-OutOfStoreReceive-Reply)
+ - [OutOfStoreReceive.Request](#weshnet-protocol-v1-OutOfStoreReceive-Request)
+ - [OutOfStoreSeal](#weshnet-protocol-v1-OutOfStoreSeal)
+ - [OutOfStoreSeal.Reply](#weshnet-protocol-v1-OutOfStoreSeal-Reply)
+ - [OutOfStoreSeal.Request](#weshnet-protocol-v1-OutOfStoreSeal-Request)
- [PeerList](#weshnet-protocol-v1-PeerList)
- [PeerList.Peer](#weshnet-protocol-v1-PeerList-Peer)
- [PeerList.Reply](#weshnet-protocol-v1-PeerList-Reply)
@@ -157,23 +163,8 @@
- [PushDeviceServerRegistered](#weshnet-protocol-v1-PushDeviceServerRegistered)
- [PushDeviceTokenRegistered](#weshnet-protocol-v1-PushDeviceTokenRegistered)
- [PushMemberTokenUpdate](#weshnet-protocol-v1-PushMemberTokenUpdate)
- - [PushReceive](#weshnet-protocol-v1-PushReceive)
- - [PushReceive.Reply](#weshnet-protocol-v1-PushReceive-Reply)
- - [PushReceive.Request](#weshnet-protocol-v1-PushReceive-Request)
- - [PushSend](#weshnet-protocol-v1-PushSend)
- - [PushSend.Reply](#weshnet-protocol-v1-PushSend-Reply)
- - [PushSend.Request](#weshnet-protocol-v1-PushSend-Request)
- [PushServer](#weshnet-protocol-v1-PushServer)
- [PushServiceReceiver](#weshnet-protocol-v1-PushServiceReceiver)
- - [PushSetDeviceToken](#weshnet-protocol-v1-PushSetDeviceToken)
- - [PushSetDeviceToken.Reply](#weshnet-protocol-v1-PushSetDeviceToken-Reply)
- - [PushSetDeviceToken.Request](#weshnet-protocol-v1-PushSetDeviceToken-Request)
- - [PushSetServer](#weshnet-protocol-v1-PushSetServer)
- - [PushSetServer.Reply](#weshnet-protocol-v1-PushSetServer-Reply)
- - [PushSetServer.Request](#weshnet-protocol-v1-PushSetServer-Request)
- - [PushShareToken](#weshnet-protocol-v1-PushShareToken)
- - [PushShareToken.Reply](#weshnet-protocol-v1-PushShareToken-Reply)
- - [PushShareToken.Request](#weshnet-protocol-v1-PushShareToken-Request)
- [RefreshContactRequest](#weshnet-protocol-v1-RefreshContactRequest)
- [RefreshContactRequest.Peer](#weshnet-protocol-v1-RefreshContactRequest-Peer)
- [RefreshContactRequest.Reply](#weshnet-protocol-v1-RefreshContactRequest-Reply)
@@ -253,7 +244,7 @@ AccountContactBlocked indicates that a contact is blocked
### AccountContactRequestAccepted
This event should be followed by an AccountGroupJoined event
-This event should be followed by GroupAddMemberDevice and GroupAddDeviceSecret events within the AccountGroup
+This event should be followed by GroupAddMemberDevice and GroupAddDeviceChainKey events within the AccountGroup
AccountContactRequestAccepted indicates that a contact request has been accepted
| Field | Type | Label | Description |
@@ -295,7 +286,7 @@ AccountContactRequestDisabled indicates that the account should be advertised on
### AccountContactRequestEnqueued
This event should be followed by an AccountGroupJoined event
This event should be followed by a GroupAddMemberDevice event within the AccountGroup
-This event should be followed by a GroupAddDeviceSecret event within the AccountGroup
+This event should be followed by a GroupAddDeviceChainKey event within the AccountGroup
AccountContactRequestEnqueued indicates that the account will attempt to send a contact request when a matching peer is discovered
| Field | Type | Label | Description |
@@ -840,10 +831,10 @@ ContactAddAliasKey is an event type where ones shares their alias public key
### DebugListGroups.Request
-
+
-### DeviceSecret
-DeviceSecret is encrypted for a specific member of the group
+### DeviceChainKey
+DeviceChainKey is a chain key, which will be encrypted for a specific member of the group
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
@@ -890,7 +881,7 @@ Group define a group and is enough to invite someone to it
| public_key | [bytes](#bytes) | | public_key is the identifier of the group, it signs the group secret and the initial member of a multi-member group |
| secret | [bytes](#bytes) | | secret is the symmetric secret of the group, which is used to encrypt the metadata |
| secret_sig | [bytes](#bytes) | | secret_sig is the signature of the secret used to ensure the validity of the group |
-| group_type | [GroupType](#weshnet-protocol-v1-GroupType) | | group_type specifies the type of the group, used to determine how device secrets are generated |
+| group_type | [GroupType](#weshnet-protocol-v1-GroupType) | | group_type specifies the type of the group, used to determine how device chain key is generated |
| sign_pub | [bytes](#bytes) | | sign_pub is the signature public key used to verify entries, not required when secret and secret_sig are provided |
| link_key | [bytes](#bytes) | | link_key is the secret key used to exchange group updates and links to attachments, useful for replication services |
| link_key_sig | [bytes](#bytes) | | link_key_sig is the signature of the link_key using the group private key |
@@ -905,10 +896,10 @@ GroupAddAdditionalRendezvousSeed indicates that an additional rendezvous point s
| device_pk | [bytes](#bytes) | | device_pk is the device sending the event, signs the message, must be the device of an admin of the group |
| seed | [bytes](#bytes) | | seed is the additional rendezvous point seed which should be used |
-
+
-### GroupAddDeviceSecret
-GroupAddDeviceSecret is an event which indicates to a group member a device secret
+### GroupAddDeviceChainKey
+GroupAddDeviceChainKey is an event which indicates to a group member a device chain key
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
@@ -920,7 +911,7 @@ GroupAddDeviceSecret is an event which indicates to a group member a device secr
### GroupAddMemberDevice
GroupAddMemberDevice is an event which indicates to a group a new device (and eventually a new member) is joining it
-When added on AccountGroup, this event should be followed by appropriate GroupAddMemberDevice and GroupAddDeviceSecret events
+When added on AccountGroup, this event should be followed by appropriate GroupAddMemberDevice and GroupAddDeviceChainKey events
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
@@ -1316,6 +1307,50 @@ OrbitDBMessageHeads is the payload sent on orbitdb to share peer's heads
| encrypted_payload | [bytes](#bytes) | | |
| nonce | [bytes](#bytes) | | |
+
+
+### OutOfStoreReceive
+
+
+
+### OutOfStoreReceive.Reply
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| message | [OutOfStoreMessage](#weshnet-protocol-v1-OutOfStoreMessage) | | |
+| cleartext | [bytes](#bytes) | | |
+| group_public_key | [bytes](#bytes) | | |
+| already_received | [bool](#bool) | | |
+
+
+
+### OutOfStoreReceive.Request
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| payload | [bytes](#bytes) | | |
+
+
+
+### OutOfStoreSeal
+
+
+
+### OutOfStoreSeal.Reply
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| encrypted | [bytes](#bytes) | | |
+
+
+
+### OutOfStoreSeal.Request
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| cid | [bytes](#bytes) | | |
+| group_public_key | [bytes](#bytes) | | |
+
### PeerList
@@ -1412,51 +1447,6 @@ Progress define a generic object that can be used to display a progress bar for
| token | [bytes](#bytes) | | |
| device_pk | [bytes](#bytes) | | device_pk is the public key of the device sending the message |
-
-
-### PushReceive
-
-
-
-### PushReceive.Reply
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| message | [OutOfStoreMessage](#weshnet-protocol-v1-OutOfStoreMessage) | | |
-| cleartext | [bytes](#bytes) | | |
-| group_public_key | [bytes](#bytes) | | |
-| already_received | [bool](#bool) | | |
-
-
-
-### PushReceive.Request
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| payload | [bytes](#bytes) | | |
-
-
-
-### PushSend
-
-
-
-### PushSend.Reply
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| group_members | [MemberWithDevices](#weshnet-protocol-v1-MemberWithDevices) | repeated | |
-
-
-
-### PushSend.Request
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| cid | [bytes](#bytes) | | |
-| group_public_key | [bytes](#bytes) | | |
-| group_members | [MemberWithDevices](#weshnet-protocol-v1-MemberWithDevices) | repeated | |
-
### PushServer
@@ -1477,56 +1467,6 @@ Progress define a generic object that can be used to display a progress bar for
| token | [bytes](#bytes) | | token is the device identifier used |
| recipient_public_key | [bytes](#bytes) | | recipient_public_key is the public key which will be used to encrypt the payload |
-
-
-### PushSetDeviceToken
-
-
-
-### PushSetDeviceToken.Reply
-
-
-
-### PushSetDeviceToken.Request
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| receiver | [PushServiceReceiver](#weshnet-protocol-v1-PushServiceReceiver) | | |
-
-
-
-### PushSetServer
-
-
-
-### PushSetServer.Reply
-
-
-
-### PushSetServer.Request
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| server | [PushServer](#weshnet-protocol-v1-PushServer) | | |
-
-
-
-### PushShareToken
-
-
-
-### PushShareToken.Reply
-
-
-
-### PushShareToken.Request
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| group_pk | [bytes](#bytes) | | |
-| server | [PushServer](#weshnet-protocol-v1-PushServer) | | |
-| receiver | [PushServiceReceiver](#weshnet-protocol-v1-PushServiceReceiver) | | |
-
### RefreshContactRequest
@@ -1835,7 +1775,7 @@ Progress define a generic object that can be used to display a progress bar for
| ---- | ------ | ----------- |
| EventTypeUndefined | 0 | EventTypeUndefined indicates that the value has not been set. Should not happen. |
| EventTypeGroupMemberDeviceAdded | 1 | EventTypeGroupMemberDeviceAdded indicates the payload includes that a member has added their device to the group |
-| EventTypeGroupDeviceSecretAdded | 2 | EventTypeGroupDeviceSecretAdded indicates the payload includes that a member has sent their device secret to another member |
+| EventTypeGroupDeviceChainKeyAdded | 2 | EventTypeGroupDeviceChainKeyAdded indicates the payload includes that a member has sent their device chain key to another member |
| EventTypeAccountGroupJoined | 101 | EventTypeAccountGroupJoined indicates the payload includes that the account has joined a group |
| EventTypeAccountGroupLeft | 102 | EventTypeAccountGroupLeft indicates the payload includes that the account has left a group |
| EventTypeAccountContactRequestDisabled | 103 | EventTypeAccountContactRequestDisabled indicates the payload includes that the account has disabled incoming contact requests |
@@ -1969,11 +1909,8 @@ Each active Wesh protocol service is considered as a Wesh device and is associat
| ServicesTokenList | [ServicesTokenList.Request](#weshnet-protocol-v1-ServicesTokenList-Request) | [ServicesTokenList.Reply](#weshnet-protocol-v1-ServicesTokenList-Reply) stream | ServicesTokenList Retrieves the list of services tokens |
| ReplicationServiceRegisterGroup | [ReplicationServiceRegisterGroup.Request](#weshnet-protocol-v1-ReplicationServiceRegisterGroup-Request) | [ReplicationServiceRegisterGroup.Reply](#weshnet-protocol-v1-ReplicationServiceRegisterGroup-Reply) | ReplicationServiceRegisterGroup Asks a replication service to distribute a group contents |
| PeerList | [PeerList.Request](#weshnet-protocol-v1-PeerList-Request) | [PeerList.Reply](#weshnet-protocol-v1-PeerList-Reply) | PeerList returns a list of P2P peers |
-| PushReceive | [PushReceive.Request](#weshnet-protocol-v1-PushReceive-Request) | [PushReceive.Reply](#weshnet-protocol-v1-PushReceive-Reply) | PushReceive handles a push payload, decrypts it if possible |
-| PushSend | [PushSend.Request](#weshnet-protocol-v1-PushSend-Request) | [PushSend.Reply](#weshnet-protocol-v1-PushSend-Reply) | PushSend sends a push payload to a specified list of group members |
-| PushShareToken | [PushShareToken.Request](#weshnet-protocol-v1-PushShareToken-Request) | [PushShareToken.Reply](#weshnet-protocol-v1-PushShareToken-Reply) | PushShareToken sends push tokens of own devices to a group |
-| PushSetDeviceToken | [PushSetDeviceToken.Request](#weshnet-protocol-v1-PushSetDeviceToken-Request) | [PushSetDeviceToken.Reply](#weshnet-protocol-v1-PushSetDeviceToken-Reply) | PushSetDeviceToken registers a push token for the current device |
-| PushSetServer | [PushSetServer.Request](#weshnet-protocol-v1-PushSetServer-Request) | [PushSetServer.Reply](#weshnet-protocol-v1-PushSetServer-Reply) | PushSetServer registers a push server for the current device |
+| OutOfStoreReceive | [OutOfStoreReceive.Request](#weshnet-protocol-v1-OutOfStoreReceive-Request) | [OutOfStoreReceive.Reply](#weshnet-protocol-v1-OutOfStoreReceive-Reply) | OutOfStoreReceive parses a payload received outside a synchronized store |
+| OutOfStoreSeal | [OutOfStoreSeal.Request](#weshnet-protocol-v1-OutOfStoreSeal-Request) | [OutOfStoreSeal.Reply](#weshnet-protocol-v1-OutOfStoreSeal-Reply) | OutOfStoreSeal creates a payload of a message present in store to be sent outside a synchronized store |
| RefreshContactRequest | [RefreshContactRequest.Request](#weshnet-protocol-v1-RefreshContactRequest-Request) | [RefreshContactRequest.Reply](#weshnet-protocol-v1-RefreshContactRequest-Reply) | RefreshContactRequest try to refresh the contact request for the given contact |
diff --git a/docs/apis/protocoltypes.swagger.json b/docs/apis/protocoltypes.swagger.json
index a515d2f2..d3593954 100644
--- a/docs/apis/protocoltypes.swagger.json
+++ b/docs/apis/protocoltypes.swagger.json
@@ -537,7 +537,7 @@
"enum": [
"EventTypeUndefined",
"EventTypeGroupMemberDeviceAdded",
- "EventTypeGroupDeviceSecretAdded",
+ "EventTypeGroupDeviceChainKeyAdded",
"EventTypeAccountGroupJoined",
"EventTypeAccountGroupLeft",
"EventTypeAccountContactRequestDisabled",
@@ -564,7 +564,7 @@
"EventTypeGroupMetadataPayloadSent"
],
"default": "EventTypeUndefined",
- "title": "- EventTypeUndefined: EventTypeUndefined indicates that the value has not been set. Should not happen.\n - EventTypeGroupMemberDeviceAdded: EventTypeGroupMemberDeviceAdded indicates the payload includes that a member has added their device to the group\n - EventTypeGroupDeviceSecretAdded: EventTypeGroupDeviceSecretAdded indicates the payload includes that a member has sent their device secret to another member\n - EventTypeAccountGroupJoined: EventTypeAccountGroupJoined indicates the payload includes that the account has joined a group\n - EventTypeAccountGroupLeft: EventTypeAccountGroupLeft indicates the payload includes that the account has left a group\n - EventTypeAccountContactRequestDisabled: EventTypeAccountContactRequestDisabled indicates the payload includes that the account has disabled incoming contact requests\n - EventTypeAccountContactRequestEnabled: EventTypeAccountContactRequestEnabled indicates the payload includes that the account has enabled incoming contact requests\n - EventTypeAccountContactRequestReferenceReset: EventTypeAccountContactRequestReferenceReset indicates the payload includes that the account has a new contact request rendezvous seed\n - EventTypeAccountContactRequestOutgoingEnqueued: EventTypeAccountContactRequestEnqueued indicates the payload includes that the account will attempt to send a new contact request\n - EventTypeAccountContactRequestOutgoingSent: EventTypeAccountContactRequestSent indicates the payload includes that the account has sent a contact request\n - EventTypeAccountContactRequestIncomingReceived: EventTypeAccountContactRequestReceived indicates the payload includes that the account has received a contact request\n - EventTypeAccountContactRequestIncomingDiscarded: EventTypeAccountContactRequestIncomingDiscarded indicates the payload includes that the account has ignored a contact request\n - EventTypeAccountContactRequestIncomingAccepted: EventTypeAccountContactRequestAccepted indicates the payload includes that the account has accepted a contact request\n - EventTypeAccountContactBlocked: EventTypeAccountContactBlocked indicates the payload includes that the account has blocked a contact\n - EventTypeAccountContactUnblocked: EventTypeAccountContactUnblocked indicates the payload includes that the account has unblocked a contact\n - EventTypeContactAliasKeyAdded: EventTypeContactAliasKeyAdded indicates the payload includes that the contact group has received an alias key\n - EventTypeMultiMemberGroupAliasResolverAdded: EventTypeMultiMemberGroupAliasResolverAdded indicates the payload includes that a member of the group sent their alias proof\n - EventTypeMultiMemberGroupInitialMemberAnnounced: EventTypeMultiMemberGroupInitialMemberAnnounced indicates the payload includes that a member has authenticated themselves as the group owner\n - EventTypeMultiMemberGroupAdminRoleGranted: EventTypeMultiMemberGroupAdminRoleGranted indicates the payload includes that an admin of the group granted another member as an admin\n - EventTypeAccountServiceTokenAdded: EventTypeAccountServiceTokenAdded indicates that a new service provider has been registered for this account\n - EventTypeAccountServiceTokenRemoved: EventTypeAccountServiceTokenRemoved indicates that a service provider is not available anymore\n - EventTypeGroupReplicating: EventTypeGroupReplicating indicates that the group has been registered for replication on a server\n - EventTypePushMemberTokenUpdate: EventTypePushMemberTokenUpdate\n - EventTypePushDeviceTokenRegistered: EventTypePushDeviceTokenRegistered\n - EventTypePushDeviceServerRegistered: EventTypePushDeviceServerRegistered\n - EventTypeAccountVerifiedCredentialRegistered: EventTypeAccountVerifiedCredentialRegistered\n - EventTypeGroupMetadataPayloadSent: EventTypeGroupMetadataPayloadSent indicates the payload includes an app specific event, unlike messages stored on the message store it is encrypted using a static key"
+ "title": "- EventTypeUndefined: EventTypeUndefined indicates that the value has not been set. Should not happen.\n - EventTypeGroupMemberDeviceAdded: EventTypeGroupMemberDeviceAdded indicates the payload includes that a member has added their device to the group\n - EventTypeGroupDeviceChainKeyAdded: EventTypeGroupDeviceChainKeyAdded indicates the payload includes that a member has sent their device chain key to another member\n - EventTypeAccountGroupJoined: EventTypeAccountGroupJoined indicates the payload includes that the account has joined a group\n - EventTypeAccountGroupLeft: EventTypeAccountGroupLeft indicates the payload includes that the account has left a group\n - EventTypeAccountContactRequestDisabled: EventTypeAccountContactRequestDisabled indicates the payload includes that the account has disabled incoming contact requests\n - EventTypeAccountContactRequestEnabled: EventTypeAccountContactRequestEnabled indicates the payload includes that the account has enabled incoming contact requests\n - EventTypeAccountContactRequestReferenceReset: EventTypeAccountContactRequestReferenceReset indicates the payload includes that the account has a new contact request rendezvous seed\n - EventTypeAccountContactRequestOutgoingEnqueued: EventTypeAccountContactRequestEnqueued indicates the payload includes that the account will attempt to send a new contact request\n - EventTypeAccountContactRequestOutgoingSent: EventTypeAccountContactRequestSent indicates the payload includes that the account has sent a contact request\n - EventTypeAccountContactRequestIncomingReceived: EventTypeAccountContactRequestReceived indicates the payload includes that the account has received a contact request\n - EventTypeAccountContactRequestIncomingDiscarded: EventTypeAccountContactRequestIncomingDiscarded indicates the payload includes that the account has ignored a contact request\n - EventTypeAccountContactRequestIncomingAccepted: EventTypeAccountContactRequestAccepted indicates the payload includes that the account has accepted a contact request\n - EventTypeAccountContactBlocked: EventTypeAccountContactBlocked indicates the payload includes that the account has blocked a contact\n - EventTypeAccountContactUnblocked: EventTypeAccountContactUnblocked indicates the payload includes that the account has unblocked a contact\n - EventTypeContactAliasKeyAdded: EventTypeContactAliasKeyAdded indicates the payload includes that the contact group has received an alias key\n - EventTypeMultiMemberGroupAliasResolverAdded: EventTypeMultiMemberGroupAliasResolverAdded indicates the payload includes that a member of the group sent their alias proof\n - EventTypeMultiMemberGroupInitialMemberAnnounced: EventTypeMultiMemberGroupInitialMemberAnnounced indicates the payload includes that a member has authenticated themselves as the group owner\n - EventTypeMultiMemberGroupAdminRoleGranted: EventTypeMultiMemberGroupAdminRoleGranted indicates the payload includes that an admin of the group granted another member as an admin\n - EventTypeAccountServiceTokenAdded: EventTypeAccountServiceTokenAdded indicates that a new service provider has been registered for this account\n - EventTypeAccountServiceTokenRemoved: EventTypeAccountServiceTokenRemoved indicates that a service provider is not available anymore\n - EventTypeGroupReplicating: EventTypeGroupReplicating indicates that the group has been registered for replication on a server\n - EventTypePushMemberTokenUpdate: EventTypePushMemberTokenUpdate\n - EventTypePushDeviceTokenRegistered: EventTypePushDeviceTokenRegistered\n - EventTypePushDeviceServerRegistered: EventTypePushDeviceServerRegistered\n - EventTypeAccountVerifiedCredentialRegistered: EventTypeAccountVerifiedCredentialRegistered\n - EventTypeGroupMetadataPayloadSent: EventTypeGroupMetadataPayloadSent indicates the payload includes an app specific event, unlike messages stored on the message store it is encrypted using a static key"
},
"v1Group": {
"type": "object",
@@ -586,7 +586,7 @@
},
"group_type": {
"$ref": "#/definitions/v1GroupType",
- "title": "group_type specifies the type of the group, used to determine how device secrets are generated"
+ "title": "group_type specifies the type of the group, used to determine how device chain key is generated"
},
"sign_pub": {
"type": "string",
@@ -718,22 +718,6 @@
"default": "GroupTypeUndefined",
"description": " - GroupTypeUndefined: GroupTypeUndefined indicates that the value has not been set. For example, happens if group is replicated.\n - GroupTypeAccount: GroupTypeAccount is the group managing an account, available to all its devices.\n - GroupTypeContact: GroupTypeContact is the group created between two accounts, available to all their devices.\n - GroupTypeMultiMember: GroupTypeMultiMember is a group containing an undefined number of members."
},
- "v1MemberWithDevices": {
- "type": "object",
- "properties": {
- "member_pk": {
- "type": "string",
- "format": "byte"
- },
- "devices_pks": {
- "type": "array",
- "items": {
- "type": "string",
- "format": "byte"
- }
- }
- }
- },
"v1MessageHeaders": {
"type": "object",
"properties": {
@@ -826,6 +810,34 @@
}
}
},
+ "v1OutOfStoreReceiveReply": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "$ref": "#/definitions/v1OutOfStoreMessage"
+ },
+ "cleartext": {
+ "type": "string",
+ "format": "byte"
+ },
+ "group_public_key": {
+ "type": "string",
+ "format": "byte"
+ },
+ "already_received": {
+ "type": "boolean"
+ }
+ }
+ },
+ "v1OutOfStoreSealReply": {
+ "type": "object",
+ "properties": {
+ "encrypted": {
+ "type": "string",
+ "format": "byte"
+ }
+ }
+ },
"v1PeerListPeer": {
"type": "object",
"properties": {
@@ -883,36 +895,6 @@
"v1ProtocolMetadata": {
"type": "object"
},
- "v1PushReceiveReply": {
- "type": "object",
- "properties": {
- "message": {
- "$ref": "#/definitions/v1OutOfStoreMessage"
- },
- "cleartext": {
- "type": "string",
- "format": "byte"
- },
- "group_public_key": {
- "type": "string",
- "format": "byte"
- },
- "already_received": {
- "type": "boolean"
- }
- }
- },
- "v1PushSendReply": {
- "type": "object",
- "properties": {
- "group_members": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/v1MemberWithDevices"
- }
- }
- }
- },
"v1PushServer": {
"type": "object",
"properties": {
@@ -962,15 +944,6 @@
"default": "PushTokenUndefined",
"title": "- PushTokenMQTT: PushTokenMQTT: Platform independent\n - PushTokenApplePushNotificationService: PushTokenApplePushNotificationService: iOS, iPadOS, tvOS, macOS\n - PushTokenFirebaseCloudMessaging: PushTokenFirebaseCloudMessaging: Android with GMS, Chrome OS\n - PushTokenWindowsPushNotificationService: PushTokenWindowsPushNotificationService: Windows, XBox\n - PushTokenHuaweiPushKit: PushTokenHuaweiPushKit: Huawei Android devices with AppGallery\n - PushTokenAmazonDeviceMessaging: PushTokenAmazonDeviceMessaging: Fire OS devices"
},
- "v1PushSetDeviceTokenReply": {
- "type": "object"
- },
- "v1PushSetServerReply": {
- "type": "object"
- },
- "v1PushShareTokenReply": {
- "type": "object"
- },
"v1RefreshContactRequestPeer": {
"type": "object",
"properties": {
diff --git a/events.go b/events.go
index 0e441893..c87d5485 100644
--- a/events.go
+++ b/events.go
@@ -18,7 +18,7 @@ var eventTypesMapper = map[protocoltypes.EventType]struct {
SigChecker sigChecker
}{
protocoltypes.EventTypeGroupMemberDeviceAdded: {Message: &protocoltypes.GroupAddMemberDevice{}, SigChecker: sigCheckerMemberDeviceAdded},
- protocoltypes.EventTypeGroupDeviceSecretAdded: {Message: &protocoltypes.GroupAddDeviceSecret{}, SigChecker: sigCheckerDeviceSigned},
+ protocoltypes.EventTypeGroupDeviceChainKeyAdded: {Message: &protocoltypes.GroupAddDeviceChainKey{}, SigChecker: sigCheckerDeviceSigned},
protocoltypes.EventTypeAccountGroupJoined: {Message: &protocoltypes.AccountGroupJoined{}, SigChecker: sigCheckerDeviceSigned},
protocoltypes.EventTypeAccountGroupLeft: {Message: &protocoltypes.AccountGroupLeft{}, SigChecker: sigCheckerDeviceSigned},
protocoltypes.EventTypeAccountContactRequestDisabled: {Message: &protocoltypes.AccountContactRequestDisabled{}, SigChecker: sigCheckerDeviceSigned},
@@ -98,7 +98,7 @@ func newGroupMetadataEventFromEntry(_ ipfslog.Log, e ipfslog.Entry, metadata *pr
}
// TODO(gfanton): getParentsCID use a lot of ressources, disable it until we need it
- // evtCtx := newEventContext(e.GetHash(), getParentsForCID(log, e.GetHash()), g, attachmentsCIDs)
+ // evtCtx := newEventContext(e.GetHash(), getParentsForCID(log, e.GetHash()), group, attachmentsCIDs)
evtCtx := newEventContext(e.GetHash(), []cid.Cid{}, g)
gme := protocoltypes.GroupMetadataEvent{
@@ -121,7 +121,7 @@ func openGroupEnvelope(g *protocoltypes.Group, envelopeBytes []byte) (*protocolt
return nil, nil, errcode.ErrSerialization.Wrap(err)
}
- data, ok := secretbox.Open(nil, env.Event, nonce, cryptoutil.GetSharedSecret(g))
+ data, ok := secretbox.Open(nil, env.Event, nonce, g.GetSharedSecret())
if !ok {
return nil, nil, errcode.ErrGroupMemberLogEventOpen
}
@@ -173,7 +173,7 @@ func sealGroupEnvelope(g *protocoltypes.Group, eventType protocoltypes.EventType
return nil, errcode.ErrSerialization.Wrap(err)
}
- eventBytes := secretbox.Seal(nil, eventClearBytes, nonce, cryptoutil.GetSharedSecret(g))
+ eventBytes := secretbox.Seal(nil, eventClearBytes, nonce, g.GetSharedSecret())
env := &protocoltypes.GroupEnvelope{
Event: eventBytes,
diff --git a/gen.sum b/gen.sum
index 5a288283..e3686c0e 100644
--- a/gen.sum
+++ b/gen.sum
@@ -1 +1 @@
-bc99bdec856c9105662f7985416c343767e8d652 Makefile
+6b8c13153a0ba512493dcc98cbf8217aba3fe330 Makefile
diff --git a/group.go b/group.go
index e8e2aa5f..dcbb63a1 100644
--- a/group.go
+++ b/group.go
@@ -1,12 +1,8 @@
package weshnet
import (
- crand "crypto/rand"
-
"github.com/libp2p/go-libp2p/core/crypto"
- "golang.org/x/crypto/nacl/box"
- "berty.tech/weshnet/pkg/cryptoutil"
"berty.tech/weshnet/pkg/errcode"
"berty.tech/weshnet/pkg/protocoltypes"
)
@@ -16,59 +12,15 @@ const CurrentGroupVersion = 1
// NewGroupMultiMember creates a new Group object and an invitation to be used by
// the first member of the group
func NewGroupMultiMember() (*protocoltypes.Group, crypto.PrivKey, error) {
- priv, pub, err := crypto.GenerateEd25519Key(crand.Reader)
- if err != nil {
- return nil, nil, errcode.ErrCryptoKeyGeneration.Wrap(err)
- }
-
- pubBytes, err := pub.Raw()
- if err != nil {
- return nil, nil, errcode.ErrSerialization.Wrap(err)
- }
-
- signing, _, err := crypto.GenerateEd25519Key(crand.Reader)
- if err != nil {
- return nil, nil, errcode.ErrCryptoKeyGeneration.Wrap(err)
- }
-
- signingBytes, err := cryptoutil.SeedFromEd25519PrivateKey(signing)
- if err != nil {
- return nil, nil, errcode.ErrSerialization.Wrap(err)
- }
-
- skSig, err := priv.Sign(signingBytes)
- if err != nil {
- return nil, nil, errcode.ErrCryptoSignature.Wrap(err)
- }
-
- group := &protocoltypes.Group{
- PublicKey: pubBytes,
- Secret: signingBytes,
- SecretSig: skSig,
- GroupType: protocoltypes.GroupTypeMultiMember,
- }
-
- updateKey, err := cryptoutil.GetLinkKeyArray(group)
- if err != nil {
- return nil, nil, errcode.ErrCryptoKeyGeneration.Wrap(err)
- }
-
- linkKeySig, err := priv.Sign(updateKey[:])
- if err != nil {
- return nil, nil, errcode.ErrCryptoSignature.Wrap(err)
- }
-
- group.LinkKeySig = linkKeySig
-
- return group, priv, nil
+ return protocoltypes.NewGroupMultiMember()
}
-func openDeviceSecret(m *protocoltypes.GroupMetadata, localMemberPrivateKey crypto.PrivKey, group *protocoltypes.Group) (crypto.PubKey, *protocoltypes.DeviceSecret, error) {
- if m == nil || m.EventType != protocoltypes.EventTypeGroupDeviceSecretAdded {
+func getAndFilterGroupAddDeviceChainKeyPayload(m *protocoltypes.GroupMetadata, localMemberPublicKey crypto.PubKey) (crypto.PubKey, []byte, error) {
+ if m == nil || m.EventType != protocoltypes.EventTypeGroupDeviceChainKeyAdded {
return nil, nil, errcode.ErrInvalidInput
}
- s := &protocoltypes.GroupAddDeviceSecret{}
+ s := &protocoltypes.GroupAddDeviceChainKey{}
if err := s.Unmarshal(m.Payload); err != nil {
return nil, nil, errcode.ErrDeserialization.Wrap(err)
}
@@ -83,44 +35,9 @@ func openDeviceSecret(m *protocoltypes.GroupMetadata, localMemberPrivateKey cryp
return nil, nil, errcode.ErrDeserialization.Wrap(err)
}
- if !localMemberPrivateKey.GetPublic().Equals(destMemberPubKey) {
+ if !localMemberPublicKey.Equals(destMemberPubKey) {
return nil, nil, errcode.ErrGroupSecretOtherDestMember
}
- mongPriv, mongPub, err := cryptoutil.EdwardsToMontgomery(localMemberPrivateKey, senderDevicePubKey)
- if err != nil {
- return nil, nil, errcode.ErrCryptoKeyConversion.Wrap(err)
- }
-
- nonce := groupIDToNonce(group)
- decryptedSecret := &protocoltypes.DeviceSecret{}
- decryptedMessage, ok := box.Open(nil, s.Payload, nonce, mongPub, mongPriv)
- if !ok {
- return nil, nil, errcode.ErrCryptoDecrypt
- }
-
- err = decryptedSecret.Unmarshal(decryptedMessage)
- if err != nil {
- return nil, nil, errcode.ErrDeserialization
- }
-
- return senderDevicePubKey, decryptedSecret, nil
-}
-
-func groupIDToNonce(group *protocoltypes.Group) *[cryptoutil.NonceSize]byte {
- // Nonce doesn't need to be secret, random nor unpredictable, it just needs
- // to be used only once for a given {sender, receiver} set and we will send
- // only one SecretEntryPayload per {localDevicePrivKey, remoteMemberPubKey}
- // So we can reuse groupID as nonce for all SecretEntryPayload and save
- // 24 bytes of storage and bandwidth for each of them.
- //
- // See https://pynacl.readthedocs.io/en/stable/secret/#nonce
- // See Security Model here: https://nacl.cr.yp.to/box.html
- var nonce [cryptoutil.NonceSize]byte
-
- gid := group.GetPublicKey()
-
- copy(nonce[:], gid)
-
- return &nonce
+ return senderDevicePubKey, s.Payload, nil
}
diff --git a/group_context.go b/group_context.go
index 8f0f748d..c784fd50 100644
--- a/group_context.go
+++ b/group_context.go
@@ -12,11 +12,11 @@ import (
"go.uber.org/zap"
"berty.tech/go-orbit-db/stores"
- "berty.tech/weshnet/pkg/cryptoutil"
"berty.tech/weshnet/pkg/errcode"
"berty.tech/weshnet/pkg/ipfsutil"
"berty.tech/weshnet/pkg/logutil"
"berty.tech/weshnet/pkg/protocoltypes"
+ "berty.tech/weshnet/pkg/secretstore"
)
type GroupContext struct {
@@ -25,18 +25,14 @@ type GroupContext struct {
group *protocoltypes.Group
metadataStore *MetadataStore
messageStore *MessageStore
- messageKeystore *cryptoutil.MessageKeystore
- memberDevice *cryptoutil.OwnMemberDevice
+ secretStore secretstore.SecretStore
+ ownMemberDevice secretstore.OwnMemberDevice
logger *zap.Logger
closed uint32
}
-func (gc *GroupContext) MessageKeystore() *cryptoutil.MessageKeystore {
- return gc.messageKeystore
-}
-
-func (gc *GroupContext) getMemberPrivKey() crypto.PrivKey {
- return gc.memberDevice.PrivateMember()
+func (gc *GroupContext) SecretStore() secretstore.SecretStore {
+ return gc.secretStore
}
func (gc *GroupContext) MessageStore() *MessageStore {
@@ -52,11 +48,11 @@ func (gc *GroupContext) Group() *protocoltypes.Group {
}
func (gc *GroupContext) MemberPubKey() crypto.PubKey {
- return gc.memberDevice.PrivateMember().GetPublic()
+ return gc.ownMemberDevice.Member()
}
func (gc *GroupContext) DevicePubKey() crypto.PubKey {
- return gc.memberDevice.PrivateDevice().GetPublic()
+ return gc.ownMemberDevice.Device()
}
func (gc *GroupContext) Close() error {
@@ -76,7 +72,7 @@ func (gc *GroupContext) IsClosed() bool {
return atomic.LoadUint32(&gc.closed) != 0
}
-func NewContextGroup(group *protocoltypes.Group, metadataStore *MetadataStore, messageStore *MessageStore, messageKeystore *cryptoutil.MessageKeystore, memberDevice *cryptoutil.OwnMemberDevice, logger *zap.Logger) *GroupContext {
+func NewContextGroup(group *protocoltypes.Group, metadataStore *MetadataStore, messageStore *MessageStore, secretStore secretstore.SecretStore, memberDevice secretstore.OwnMemberDevice, logger *zap.Logger) *GroupContext {
ctx, cancel := context.WithCancel(context.Background())
if logger == nil {
@@ -89,8 +85,8 @@ func NewContextGroup(group *protocoltypes.Group, metadataStore *MetadataStore, m
group: group,
metadataStore: metadataStore,
messageStore: messageStore,
- messageKeystore: messageKeystore,
- memberDevice: memberDevice,
+ secretStore: secretStore,
+ ownMemberDevice: memberDevice,
logger: logger.With(logutil.PrivateString("group-id", fmt.Sprintf("%.6s", base64.StdEncoding.EncodeToString(group.PublicKey)))),
closed: 0,
}
@@ -112,7 +108,7 @@ func (gc *GroupContext) activateGroupContext(contact crypto.PubKey, selfAnnounce
chNewData := gc.FillMessageKeysHolderUsingNewData()
go func() {
for pk := range chNewData {
- if !pk.Equals(gc.memberDevice.PrivateDevice().GetPublic()) {
+ if !pk.Equals(gc.ownMemberDevice.Device()) {
gc.logger.Warn("gc member device public key doesn't match")
}
}
@@ -122,7 +118,7 @@ func (gc *GroupContext) activateGroupContext(contact crypto.PubKey, selfAnnounce
go func() {
calledDone := false
for pk := range chMember {
- if !pk.Equals(gc.memberDevice.PrivateMember().GetPublic()) {
+ if !pk.Equals(gc.ownMemberDevice.Member()) {
gc.logger.Warn("gc member device public key doesn't match")
continue
}
@@ -143,7 +139,7 @@ func (gc *GroupContext) activateGroupContext(contact crypto.PubKey, selfAnnounce
chPreviousData := gc.FillMessageKeysHolderUsingPreviousData()
go func() {
for pk := range chPreviousData {
- if !pk.Equals(gc.memberDevice.PrivateDevice().GetPublic()) {
+ if !pk.Equals(gc.ownMemberDevice.Device()) {
gc.logger.Warn("gc member device public key doesn't match")
}
}
@@ -155,7 +151,7 @@ func (gc *GroupContext) activateGroupContext(contact crypto.PubKey, selfAnnounce
chSecrets := gc.SendSecretsToExistingMembers(contact)
go func() {
for pk := range chSecrets {
- if !pk.Equals(gc.memberDevice.PrivateMember().GetPublic()) {
+ if !pk.Equals(gc.ownMemberDevice.Member()) {
gc.logger.Warn("gc member device public key doesn't match")
}
}
@@ -215,11 +211,11 @@ func (gc *GroupContext) FillMessageKeysHolderUsingNewData() <-chan crypto.PubKey
}
e := evt.(protocoltypes.GroupMetadataEvent)
- if e.Metadata.EventType != protocoltypes.EventTypeGroupDeviceSecretAdded {
+ if e.Metadata.EventType != protocoltypes.EventTypeGroupDeviceChainKeyAdded {
continue
}
- pk, ds, err := openDeviceSecret(e.Metadata, gc.getMemberPrivKey(), gc.Group())
+ senderPublicKey, encryptedDeviceChainKey, err := getAndFilterGroupAddDeviceChainKeyPayload(e.Metadata, gc.ownMemberDevice.Member())
if errcode.Is(err, errcode.ErrInvalidInput) {
continue
}
@@ -229,21 +225,21 @@ func (gc *GroupContext) FillMessageKeysHolderUsingNewData() <-chan crypto.PubKey
}
if err != nil {
- gc.logger.Error("an error occurred while opening device secrets", zap.Error(err))
+ gc.logger.Error("an error occurred while opening device chain key", zap.Error(err))
continue
}
- if err = gc.MessageKeystore().RegisterChainKey(gc.ctx, gc.Group(), pk, ds, gc.DevicePubKey().Equals(pk)); err != nil {
+ if err = gc.SecretStore().RegisterChainKey(gc.ctx, gc.Group(), senderPublicKey, encryptedDeviceChainKey); err != nil {
gc.logger.Error("unable to register chain key", zap.Error(err))
continue
}
// A new chainKey is registered, check if cached messages can be opened with it
- if rawPK, err := pk.Raw(); err == nil {
+ if rawPK, err := senderPublicKey.Raw(); err == nil {
gc.MessageStore().ProcessMessageQueueForDevicePK(gc.ctx, rawPK)
}
- ch <- pk
+ ch <- senderPublicKey
}
}()
@@ -305,17 +301,17 @@ func (gc *GroupContext) FillMessageKeysHolderUsingPreviousData() <-chan crypto.P
publishedSecrets := gc.metadataStoreListSecrets()
go func() {
- for pk, sec := range publishedSecrets {
- if err := gc.MessageKeystore().RegisterChainKey(gc.ctx, gc.Group(), pk, sec, gc.DevicePubKey().Equals(pk)); err != nil {
+ for senderPublicKey, encryptedSecret := range publishedSecrets {
+ if err := gc.SecretStore().RegisterChainKey(gc.ctx, gc.Group(), senderPublicKey, encryptedSecret); err != nil {
gc.logger.Error("unable to register chain key", zap.Error(err))
continue
}
// A new chainKey is registered, check if cached messages can be opened with it
- if rawPK, err := pk.Raw(); err == nil {
+ if rawPK, err := senderPublicKey.Raw(); err == nil {
gc.MessageStore().ProcessMessageQueueForDevicePK(gc.ctx, rawPK)
}
- ch <- pk
+ ch <- senderPublicKey
}
close(ch)
@@ -324,13 +320,10 @@ func (gc *GroupContext) FillMessageKeysHolderUsingPreviousData() <-chan crypto.P
return ch
}
-func (gc *GroupContext) metadataStoreListSecrets() map[crypto.PubKey]*protocoltypes.DeviceSecret {
- publishedSecrets := map[crypto.PubKey]*protocoltypes.DeviceSecret{}
+func (gc *GroupContext) metadataStoreListSecrets() map[crypto.PubKey][]byte {
+ publishedSecrets := map[crypto.PubKey][]byte{}
m := gc.MetadataStore()
- ownSK := gc.getMemberPrivKey()
- g := gc.Group()
-
metadatas, err := m.ListEvents(gc.ctx, nil, nil, false)
if err != nil {
return nil
@@ -340,17 +333,17 @@ func (gc *GroupContext) metadataStoreListSecrets() map[crypto.PubKey]*protocolty
continue
}
- pk, ds, err := openDeviceSecret(metadata.Metadata, ownSK, g)
+ pk, encryptedDeviceChainKey, err := getAndFilterGroupAddDeviceChainKeyPayload(metadata.Metadata, gc.MemberPubKey())
if errcode.Is(err, errcode.ErrInvalidInput) || errcode.Is(err, errcode.ErrGroupSecretOtherDestMember) {
continue
}
if err != nil {
- gc.logger.Error("unable to open device secret", zap.Error(err))
+ gc.logger.Error("unable to open device chain key", zap.Error(err))
continue
}
- publishedSecrets[pk] = ds
+ publishedSecrets[pk] = encryptedDeviceChainKey
}
return publishedSecrets
diff --git a/group_test.go b/group_test.go
deleted file mode 100644
index fbe95f3a..00000000
--- a/group_test.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package weshnet
-
-import (
- crand "crypto/rand"
- "testing"
-
- "github.com/libp2p/go-libp2p/core/crypto"
- "github.com/stretchr/testify/require"
-
- "berty.tech/weshnet/pkg/cryptoutil"
- "berty.tech/weshnet/pkg/protocoltypes"
-)
-
-func TestGetGroupForContact(t *testing.T) {
- sk, _, err := crypto.GenerateEd25519Key(crand.Reader)
- require.NoError(t, err)
-
- g, err := cryptoutil.GetGroupForContact(sk)
- require.NoError(t, err)
-
- require.Equal(t, g.GroupType, protocoltypes.GroupTypeContact)
- require.Equal(t, len(g.PublicKey), 32)
- require.Equal(t, len(g.Secret), 32)
-}
-
-func TestGetKeysForGroupOfContact(t *testing.T) {
- sk, _, err := crypto.GenerateEd25519Key(crand.Reader)
- require.NoError(t, err)
-
- sk1, sk2, err := cryptoutil.GetKeysForGroupOfContact(sk)
- require.NoError(t, err)
-
- require.NotNil(t, sk1)
- require.NotNil(t, sk2)
- require.False(t, sk1.Equals(sk2))
-}
diff --git a/iface_account.go b/iface_account.go
index 099bdcb3..945eec8f 100644
--- a/iface_account.go
+++ b/iface_account.go
@@ -1,15 +1,10 @@
package weshnet
import (
- crand "crypto/rand"
- "math"
- "math/big"
-
"github.com/libp2p/go-libp2p/core/crypto"
- "berty.tech/weshnet/pkg/cryptoutil"
- "berty.tech/weshnet/pkg/errcode"
"berty.tech/weshnet/pkg/protocoltypes"
+ "berty.tech/weshnet/pkg/secretstore"
)
type AccountKeys interface {
@@ -17,30 +12,5 @@ type AccountKeys interface {
AccountProofPrivKey() (crypto.PrivKey, error)
DevicePrivKey() (crypto.PrivKey, error)
ContactGroupPrivKey(pk crypto.PubKey) (crypto.PrivKey, error)
- MemberDeviceForGroup(g *protocoltypes.Group) (*cryptoutil.OwnMemberDevice, error)
-}
-
-// MemberDevice is a remote device part of a group
-type MemberDevice struct {
- Member crypto.PubKey
- Device crypto.PubKey
- Secret *protocoltypes.DeviceSecret
-}
-
-func NewDeviceSecret() (*protocoltypes.DeviceSecret, error) {
- counter, err := crand.Int(crand.Reader, big.NewInt(0).SetUint64(math.MaxUint64))
- if err != nil {
- return nil, errcode.ErrCryptoRandomGeneration.Wrap(err)
- }
-
- chainKey := make([]byte, 32)
- _, err = crand.Read(chainKey)
- if err != nil {
- return nil, errcode.ErrCryptoRandomGeneration.Wrap(err)
- }
-
- return &protocoltypes.DeviceSecret{
- ChainKey: chainKey,
- Counter: counter.Uint64(),
- }, nil
+ MemberDeviceForGroup(g *protocoltypes.Group) (secretstore.OwnMemberDevice, error)
}
diff --git a/internal/datastoreutil/consts.go b/internal/datastoreutil/consts.go
index 919d2b98..ea63efd1 100644
--- a/internal/datastoreutil/consts.go
+++ b/internal/datastoreutil/consts.go
@@ -1,7 +1,5 @@
package datastoreutil
const (
- AccountCacheDatastorePushServerPK = "push_server_public_key"
- NamespaceAccountCacheDatastore = "account_cache_datastore"
- NamespaceMessageKeystore = "messages_keystore"
+ NamespaceMessageKeystore = "messages_keystore"
)
diff --git a/message_marshaler.go b/message_marshaler.go
index fd4df01c..783ba121 100644
--- a/message_marshaler.go
+++ b/message_marshaler.go
@@ -12,9 +12,9 @@ import (
"berty.tech/go-ipfs-log/enc"
"berty.tech/go-ipfs-log/entry"
"berty.tech/go-orbit-db/iface"
- "berty.tech/weshnet/pkg/cryptoutil"
"berty.tech/weshnet/pkg/protocoltypes"
"berty.tech/weshnet/pkg/rendezvous"
+ "berty.tech/weshnet/pkg/secretstore"
)
type PeerDeviceGroup struct {
@@ -29,20 +29,20 @@ type OrbitDBMessageMarshaler struct {
deviceCaches map[peer.ID]*PeerDeviceGroup
muMarshall sync.RWMutex
selfid peer.ID
- dk cryptoutil.DeviceKeystore
+ secretStore secretstore.SecretStore
// in Replication Mode DeviceKey should not be sent
useReplicationMode bool
}
-func NewOrbitDBMessageMarshaler(selfid peer.ID, dk cryptoutil.DeviceKeystore, rp *rendezvous.RotationInterval, useReplicationMode bool) *OrbitDBMessageMarshaler {
+func NewOrbitDBMessageMarshaler(selfid peer.ID, secretStore secretstore.SecretStore, rp *rendezvous.RotationInterval, useReplicationMode bool) *OrbitDBMessageMarshaler {
return &OrbitDBMessageMarshaler{
selfid: selfid,
sharedKeys: make(map[string]enc.SharedKey),
deviceCaches: make(map[peer.ID]*PeerDeviceGroup),
topicGroup: make(map[string]*protocoltypes.Group),
rp: rp,
- dk: dk,
+ secretStore: secretStore,
useReplicationMode: useReplicationMode,
}
}
@@ -94,12 +94,12 @@ func (m *OrbitDBMessageMarshaler) Marshal(msg *iface.MessageExchangeHeads) ([]by
// in replication mode, it doesn't make sense to send DevicePK
if !m.useReplicationMode {
- ownDevice, err := m.dk.MemberDeviceForGroup(group)
+ ownDevice, err := m.secretStore.GetOwnMemberDeviceForGroup(group)
if err != nil {
return nil, fmt.Errorf("unable to get own member device key for group: %w", err)
}
- ownPK, err = ownDevice.PrivateDevice().GetPublic().Raw()
+ ownPK, err = ownDevice.Device().Raw()
if err != nil {
return nil, fmt.Errorf("unable to get raw pk for device: %w", err)
}
diff --git a/message_marshaler_test.go b/message_marshaler_test.go
index 4c58fa0d..4c761619 100644
--- a/message_marshaler_test.go
+++ b/message_marshaler_test.go
@@ -4,7 +4,6 @@ import (
"testing"
"time"
- keystore "github.com/ipfs/go-ipfs-keystore"
mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -12,8 +11,8 @@ import (
"berty.tech/go-ipfs-log/enc"
"berty.tech/go-ipfs-log/entry"
"berty.tech/go-orbit-db/iface"
- "berty.tech/weshnet/pkg/cryptoutil"
"berty.tech/weshnet/pkg/rendezvous"
+ "berty.tech/weshnet/pkg/secretstore"
)
var (
@@ -37,8 +36,8 @@ func TestRotationMessageMarshaler(t *testing.T) {
require.NoError(t, err)
// generate keystore
- ks1 := keystore.NewMemKeystore()
- acc1 := cryptoutil.NewDeviceKeystore(ks1, nil)
+ acc1, err := secretstore.NewInMemSecretStore(nil)
+ require.NoError(t, err)
rp := rendezvous.NewStaticRotationInterval()
m := NewOrbitDBMessageMarshaler(p.ID(), acc1, rp, false)
@@ -76,8 +75,8 @@ func TestRotationMessageMarshalUnknownTopic(t *testing.T) {
require.NoError(t, err)
// generate keystore
- ks := keystore.NewMemKeystore()
- acc := cryptoutil.NewDeviceKeystore(ks, nil)
+ acc, err := secretstore.NewInMemSecretStore(nil)
+ require.NoError(t, err)
rp := rendezvous.NewStaticRotationInterval()
m := NewOrbitDBMessageMarshaler(p.ID(), acc, rp, false)
@@ -109,11 +108,11 @@ func TestRotationMessageUnmarshalUnknownTopic(t *testing.T) {
require.NoError(t, err)
// generate keystore
- ks1 := keystore.NewMemKeystore()
- acc1 := cryptoutil.NewDeviceKeystore(ks1, nil)
+ acc1, err := secretstore.NewInMemSecretStore(nil)
+ require.NoError(t, err)
- ks2 := keystore.NewMemKeystore()
- acc2 := cryptoutil.NewDeviceKeystore(ks2, nil)
+ acc2, err := secretstore.NewInMemSecretStore(nil)
+ require.NoError(t, err)
g1, _, err := NewGroupMultiMember()
require.NoError(t, err)
@@ -175,11 +174,11 @@ func TestRotationMessageMarshalWrongKey(t *testing.T) {
require.NoError(t, err)
// generate keystore
- ks1 := keystore.NewMemKeystore()
- acc1 := cryptoutil.NewDeviceKeystore(ks1, nil)
+ acc1, err := secretstore.NewInMemSecretStore(nil)
+ require.NoError(t, err)
- ks2 := keystore.NewMemKeystore()
- acc2 := cryptoutil.NewDeviceKeystore(ks2, nil)
+ acc2, err := secretstore.NewInMemSecretStore(nil)
+ require.NoError(t, err)
rp1 := rendezvous.NewStaticRotationInterval()
rp1.RegisterRotation(time.Now(), msg.Address, testSeed1)
diff --git a/orbitdb.go b/orbitdb.go
index 6513b477..e7c20bde 100644
--- a/orbitdb.go
+++ b/orbitdb.go
@@ -27,12 +27,11 @@ import (
"berty.tech/go-orbit-db/iface"
"berty.tech/go-orbit-db/pubsub/pubsubcoreapi"
"berty.tech/go-orbit-db/stores"
- "berty.tech/weshnet/internal/datastoreutil"
- "berty.tech/weshnet/pkg/cryptoutil"
"berty.tech/weshnet/pkg/errcode"
"berty.tech/weshnet/pkg/ipfsutil"
"berty.tech/weshnet/pkg/protocoltypes"
"berty.tech/weshnet/pkg/rendezvous"
+ "berty.tech/weshnet/pkg/secretstore"
"berty.tech/weshnet/pkg/tyber"
)
@@ -53,13 +52,12 @@ type loggable interface {
type NewOrbitDBOptions struct {
baseorbitdb.NewOrbitDBOptions
Datastore datastore.Batching
- MessageKeystore *cryptoutil.MessageKeystore
- DeviceKeystore cryptoutil.DeviceKeystore
+ SecretStore secretstore.SecretStore
RotationInterval *rendezvous.RotationInterval
- ReplicationMode bool
GroupMetadataStoreType string
GroupMessageStoreType string
+ ReplicationMode bool
}
func (n *NewOrbitDBOptions) applyDefaults() {
@@ -75,14 +73,6 @@ func (n *NewOrbitDBOptions) applyDefaults() {
n.Logger = zap.NewNop()
}
- if n.MessageKeystore == nil {
- n.MessageKeystore = cryptoutil.NewMessageKeystore(datastoreutil.NewNamespacedDatastore(n.Datastore, datastore.NewKey(datastoreutil.NamespaceMessageKeystore)), n.Logger)
- }
-
- if n.DeviceKeystore == nil {
- n.DeviceKeystore = cryptoutil.NewDeviceKeystore(ipfsutil.NewDatastoreKeystore(datastoreutil.NewNamespacedDatastore(n.Datastore, datastore.NewKey(NamespaceDeviceKeystore))), nil)
- }
-
if n.RotationInterval == nil {
n.RotationInterval = rendezvous.NewStaticRotationInterval()
}
@@ -110,11 +100,11 @@ type (
type WeshOrbitDB struct {
baseorbitdb.BaseOrbitDB
keyStore *BertySignedKeyStore
- messageKeystore *cryptoutil.MessageKeystore
- deviceKeystore cryptoutil.DeviceKeystore
+ secretStore secretstore.SecretStore
pubSub iface.PubSubInterface
rotationInterval *rendezvous.RotationInterval
messageMarshaler *OrbitDBMessageMarshaler
+ replicationMode bool
groupMetadataStoreType string
groupMessageStoreType string
@@ -189,7 +179,7 @@ func NewWeshOrbitDB(ctx context.Context, ipfs coreapi.CoreAPI, options *NewOrbit
options.PubSub = pubsubcoreapi.NewPubSub(ipfs, self.ID(), time.Second, options.Logger, options.Tracer)
}
- mm := NewOrbitDBMessageMarshaler(self.ID(), options.DeviceKeystore, options.RotationInterval, options.ReplicationMode)
+ mm := NewOrbitDBMessageMarshaler(self.ID(), options.SecretStore, options.RotationInterval, options.ReplicationMode)
options.MessageMarshaler = mm
orbitDB, err := baseorbitdb.NewOrbitDB(ctx, ipfs, &options.NewOrbitDBOptions)
@@ -198,20 +188,19 @@ func NewWeshOrbitDB(ctx context.Context, ipfs coreapi.CoreAPI, options *NewOrbit
}
bertyDB := &WeshOrbitDB{
- ctx: ctx,
- messageMarshaler: mm,
- BaseOrbitDB: orbitDB,
- keyStore: ks,
- deviceKeystore: options.DeviceKeystore,
- messageKeystore: options.MessageKeystore,
- rotationInterval: options.RotationInterval,
- pubSub: options.PubSub,
- groups: &GroupMap{},
- groupContexts: &GroupContextMap{}, // map[string]*GroupContext
- groupsSigPubKey: &GroupsSigPubKeyMap{}, // map[string]crypto.PubKey
-
+ ctx: ctx,
+ messageMarshaler: mm,
+ BaseOrbitDB: orbitDB,
+ keyStore: ks,
+ secretStore: options.SecretStore,
+ rotationInterval: options.RotationInterval,
+ pubSub: options.PubSub,
+ groups: &GroupMap{},
+ groupContexts: &GroupContextMap{}, // map[string]*GroupContext
+ groupsSigPubKey: &GroupsSigPubKeyMap{}, // map[string]crypto.PubKey
groupMetadataStoreType: options.GroupMetadataStoreType,
groupMessageStoreType: options.GroupMessageStoreType,
+ replicationMode: options.ReplicationMode,
}
if err := bertyDB.RegisterAccessControllerType(NewSimpleAccessController); err != nil {
@@ -234,34 +223,21 @@ func (s *WeshOrbitDB) openAccountGroup(ctx context.Context, options *orbitdb.Cre
options.EventBus = s.EventBus()
}
- sk, err := s.deviceKeystore.AccountPrivKey()
- if err != nil {
- return nil, errcode.ErrOrbitDBOpen.Wrap(err)
- }
- l.Debug("Got AccountPrivKey", tyber.FormatStepLogFields(ctx, []tyber.Detail{})...)
-
- skProof, err := s.deviceKeystore.AccountProofPrivKey()
- if err != nil {
- return nil, errcode.ErrOrbitDBOpen.Wrap(err)
- }
-
- l.Debug("Got AccountProofPrivKey", tyber.FormatStepLogFields(ctx, []tyber.Detail{})...)
-
- g, err := cryptoutil.GetGroupForAccount(sk, skProof)
+ group, _, err := s.secretStore.GetGroupForAccount()
if err != nil {
return nil, errcode.ErrOrbitDBOpen.Wrap(err)
}
- l.Debug("Got account group", tyber.FormatStepLogFields(ctx, []tyber.Detail{{Name: "Group", Description: g.String()}})...)
+ l.Debug("Got account group", tyber.FormatStepLogFields(ctx, []tyber.Detail{{Name: "Group", Description: group.String()}})...)
- gc, err := s.OpenGroup(ctx, g, options)
+ gc, err := s.OpenGroup(ctx, group, options)
if err != nil {
return nil, errcode.ErrGroupOpen.Wrap(err)
}
l.Debug("Opened account group", tyber.FormatStepLogFields(ctx, []tyber.Detail{})...)
- if err := gc.ActivateGroupContext(nil); err != nil {
+ if err := gc.ActivateGroupContext(gc.ownMemberDevice.Member()); err != nil {
return nil, errcode.TODO.Wrap(err)
}
@@ -400,7 +376,7 @@ func (s *WeshOrbitDB) loadHeads(ctx context.Context, store iface.Store, heads []
}
func (s *WeshOrbitDB) OpenGroup(ctx context.Context, g *protocoltypes.Group, options *orbitdb.CreateDBOptions) (*GroupContext, error) {
- if s.deviceKeystore == nil || s.messageKeystore == nil {
+ if s.secretStore == nil {
return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("db open in naive mode"))
}
@@ -423,23 +399,23 @@ func (s *WeshOrbitDB) OpenGroup(ctx context.Context, g *protocoltypes.Group, opt
s.Logger().Debug("OpenGroup", tyber.FormatStepLogFields(s.ctx, tyber.ZapFieldsToDetails(zap.Any("public key", g.PublicKey), zap.Any("secret", g.Secret), zap.Stringer("type", g.GroupType)))...)
- memberDevice, err := s.deviceKeystore.MemberDeviceForGroup(g)
+ memberDevice, err := s.secretStore.GetOwnMemberDeviceForGroup(g)
if err != nil {
return nil, errcode.ErrCryptoKeyGeneration.Wrap(err)
}
- mpkb, err := crypto.MarshalPublicKey(memberDevice.Public().Member)
+ mpkb, err := crypto.MarshalPublicKey(memberDevice.Member())
if err != nil {
mpkb = []byte{}
}
s.Logger().Debug("Got member device", tyber.FormatStepLogFields(s.ctx, []tyber.Detail{{Name: "DevicePublicKey", Description: base64.RawURLEncoding.EncodeToString(mpkb)}})...)
// Force secret generation if missing
- if _, err := s.messageKeystore.GetDeviceSecret(s.ctx, g, s.deviceKeystore); err != nil {
+ if _, err := s.secretStore.GetShareableChainKey(s.ctx, g, memberDevice.Member()); err != nil {
return nil, errcode.ErrCryptoKeyGeneration.Wrap(err)
}
- s.Logger().Debug("Got device secret", tyber.FormatStepLogFields(s.ctx, []tyber.Detail{})...)
+ s.Logger().Debug("Got device chain key", tyber.FormatStepLogFields(s.ctx, []tyber.Detail{})...)
metaImpl, err := s.groupMetadataStore(ctx, g, options)
if err != nil {
@@ -464,7 +440,7 @@ func (s *WeshOrbitDB) OpenGroup(ctx context.Context, g *protocoltypes.Group, opt
s.Logger().Debug("Got message store", tyber.FormatStepLogFields(s.ctx, []tyber.Detail{})...)
- gc := NewContextGroup(g, metaImpl, messagesImpl, s.messageKeystore, memberDevice, s.Logger())
+ gc := NewContextGroup(g, metaImpl, messagesImpl, s.secretStore, memberDevice, s.Logger())
s.Logger().Debug("Created group context", tyber.FormatStepLogFields(s.ctx, []tyber.Detail{})...)
@@ -562,7 +538,7 @@ func (s *WeshOrbitDB) storeForGroup(ctx context.Context, o iface.BaseOrbitDB, g
s.messageMarshaler.RegisterGroup(addr.String(), g)
- linkKey, err := cryptoutil.GetLinkKeyArray(g)
+ linkKey, err := g.GetLinkKeyArray()
if err != nil {
return nil, err
}
diff --git a/orbitdb_many_adds_berty_test.go b/orbitdb_many_adds_berty_test.go
index 1faa1607..1fae5989 100644
--- a/orbitdb_many_adds_berty_test.go
+++ b/orbitdb_many_adds_berty_test.go
@@ -18,6 +18,7 @@ import (
"berty.tech/go-orbit-db/iface"
"berty.tech/weshnet/pkg/ipfsutil"
"berty.tech/weshnet/pkg/protocoltypes"
+ "berty.tech/weshnet/pkg/secretstore"
"berty.tech/weshnet/pkg/testutil"
)
@@ -42,8 +43,13 @@ func testAddBerty(ctx context.Context, t *testing.T, node ipfsutil.CoreAPIMock,
baseDS = sync_ds.MutexWrap(baseDS)
defer testutil.Close(t, baseDS)
+ secretStore, err := secretstore.NewSecretStore(baseDS, nil)
+ require.NoError(t, err)
+ defer secretStore.Close()
+
odb, err := NewWeshOrbitDB(ctx, api, &NewOrbitDBOptions{
- Datastore: baseDS,
+ Datastore: baseDS,
+ SecretStore: secretStore,
})
require.NoError(t, err)
diff --git a/orbitdb_utils_test.go b/orbitdb_utils_test.go
index aace53ad..6ca1f82c 100644
--- a/orbitdb_utils_test.go
+++ b/orbitdb_utils_test.go
@@ -102,7 +102,7 @@ func waitForBertyEventType(ctx context.Context, t *testing.T, ms *MetadataStore,
handledEvents[eID] = struct{}{}
- e := &protocoltypes.GroupAddDeviceSecret{}
+ e := &protocoltypes.GroupAddDeviceChainKey{}
if err := e.Unmarshal(evt.Event); err != nil {
t.Fatalf(" err: %+v\n", err.Error())
}
diff --git a/pkg/bertypush/push_handler.go b/pkg/bertypush/push_handler.go
deleted file mode 100644
index 2bc9b250..00000000
--- a/pkg/bertypush/push_handler.go
+++ /dev/null
@@ -1,290 +0,0 @@
-package bertypush
-
-import (
- "context"
- "fmt"
- "time"
-
- ds "github.com/ipfs/go-datastore"
- ds_sync "github.com/ipfs/go-datastore/sync"
- "github.com/libp2p/go-libp2p/core/crypto"
- "go.uber.org/zap"
- "golang.org/x/crypto/curve25519"
- "golang.org/x/crypto/nacl/box"
- "golang.org/x/crypto/nacl/secretbox"
-
- "berty.tech/weshnet/internal/datastoreutil"
- "berty.tech/weshnet/pkg/cryptoutil"
- "berty.tech/weshnet/pkg/errcode"
- "berty.tech/weshnet/pkg/protocoltypes"
- "berty.tech/weshnet/pkg/pushtypes"
-)
-
-const InMemoryDir = ":memory:"
-
-type pushHandler struct {
- logger *zap.Logger
- pushSK *[cryptoutil.KeySize]byte
- pushPK *[cryptoutil.KeySize]byte
- groupDatastore cryptoutil.GroupDatastoreReadOnly
- messageKeystore *cryptoutil.MessageKeystore
- accountCache ds.Datastore
-}
-
-func (s *pushHandler) UpdatePushServer(ctx context.Context, server *protocoltypes.PushServer) error {
- cachePayload, err := server.Marshal()
- if err != nil {
- return errcode.ErrSerialization.Wrap(fmt.Errorf("unable to marshal PushServer: %w", err))
- }
-
- err = s.accountCache.Put(ctx, ds.NewKey(datastoreutil.AccountCacheDatastorePushServerPK), cachePayload)
- if err != nil {
- return errcode.ErrInternal.Wrap(fmt.Errorf("unable to cache push server info: %s", err))
- }
-
- return nil
-}
-
-func (s *pushHandler) PushPK() *[cryptoutil.KeySize]byte {
- return s.pushPK
-}
-
-func (s *pushHandler) SetPushSK(key *[cryptoutil.KeySize]byte) {
- s.pushSK = key
- curve25519.ScalarBaseMult(s.pushPK, s.pushSK)
-}
-
-type PushHandler interface {
- PushReceive(ctx context.Context, payload []byte) (*protocoltypes.PushReceive_Reply, error)
- PushPK() *[cryptoutil.KeySize]byte
- UpdatePushServer(ctx context.Context, server *protocoltypes.PushServer) error
-}
-
-var _ PushHandler = (*pushHandler)(nil)
-
-type PushHandlerOpts struct {
- Logger *zap.Logger
- PushKey *[cryptoutil.KeySize]byte
- DatastoreDir string
- RootDatastore ds.Datastore
- GroupDatastore *cryptoutil.GroupDatastore
- MessageKeystore *cryptoutil.MessageKeystore
- AccountCache ds.Datastore
-}
-
-func (opts *PushHandlerOpts) applyPushDefaults() error {
- if opts.Logger == nil {
- opts.Logger = zap.NewNop()
- }
-
- if opts.RootDatastore == nil {
- if opts.DatastoreDir == "" || opts.DatastoreDir == InMemoryDir {
- opts.RootDatastore = ds_sync.MutexWrap(ds.NewMapDatastore())
- } else {
- opts.RootDatastore = nil
- }
- }
-
- if opts.GroupDatastore == nil {
- var err error
- opts.GroupDatastore, err = cryptoutil.NewGroupDatastore(opts.RootDatastore)
- if err != nil {
- return err
- }
- }
-
- if opts.AccountCache == nil {
- opts.AccountCache = datastoreutil.NewNamespacedDatastore(opts.RootDatastore, ds.NewKey(datastoreutil.NamespaceAccountCacheDatastore))
- }
-
- if opts.MessageKeystore == nil {
- opts.MessageKeystore = cryptoutil.NewMessageKeystore(datastoreutil.NewNamespacedDatastore(opts.RootDatastore, ds.NewKey(datastoreutil.NamespaceMessageKeystore)), opts.Logger)
- }
-
- return nil
-}
-
-func NewPushHandler(opts *PushHandlerOpts) (PushHandler, error) {
- if opts.PushKey == nil {
- return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("no cross account push key specified"))
- }
-
- if err := opts.applyPushDefaults(); err != nil {
- return nil, err
- }
-
- h := &pushHandler{
- logger: opts.Logger,
- pushSK: opts.PushKey,
- pushPK: &[cryptoutil.KeySize]byte{},
- groupDatastore: opts.GroupDatastore,
- messageKeystore: opts.MessageKeystore,
- accountCache: opts.AccountCache,
- }
-
- curve25519.ScalarBaseMult(h.pushPK, h.pushSK)
-
- return h, nil
-}
-
-func (s *pushHandler) PushReceive(ctx context.Context, payload []byte) (*protocoltypes.PushReceive_Reply, error) {
- pushServerPK, err := s.getServerPushPubKey(ctx)
- if err != nil {
- return nil, errcode.ErrPushUnableToDecrypt.Wrap(err)
- }
-
- oosBytes, err := DecryptPushDataFromServer(payload, pushServerPK, s.pushSK)
- if err != nil {
- return nil, errcode.ErrPushUnableToDecrypt.Wrap(err)
- }
-
- oosMessageEnv := &pushtypes.OutOfStoreMessageEnvelope{}
- if err := oosMessageEnv.Unmarshal(oosBytes); err != nil {
- return nil, errcode.ErrDeserialization.Wrap(err)
- }
-
- gPKBytes, err := s.messageKeystore.GetByPushGroupReference(ctx, oosMessageEnv.GroupReference)
- if err != nil {
- return nil, errcode.ErrNotFound.Wrap(err)
- }
-
- gPK, err := crypto.UnmarshalEd25519PublicKey(gPKBytes)
- if err != nil {
- return nil, errcode.ErrDeserialization.Wrap(err)
- }
-
- oosMessage, err := DecryptOutOfStoreMessageEnv(ctx, s.groupDatastore, oosMessageEnv, gPK)
- if err != nil {
- return nil, errcode.ErrCryptoDecrypt.Wrap(err)
- }
-
- clear, newlyDecrypted, err := s.messageKeystore.OpenOutOfStoreMessage(ctx, oosMessage, gPKBytes)
- if err != nil {
- return nil, errcode.ErrCryptoDecrypt.Wrap(err)
- }
-
- g, err := s.groupDatastore.Get(ctx, gPK)
- if err == nil {
- if err := s.messageKeystore.UpdatePushGroupReferences(ctx, oosMessage.DevicePK, oosMessage.Counter, g); err != nil {
- s.logger.Error("unable to update push group references", zap.Error(err))
- }
- }
-
- return &protocoltypes.PushReceive_Reply{
- Message: oosMessage,
- Cleartext: clear,
- GroupPublicKey: gPKBytes,
- AlreadyReceived: !newlyDecrypted,
- }, nil
-}
-
-func DecryptOutOfStoreMessageEnv(ctx context.Context, gd cryptoutil.GroupDatastoreReadOnly, env *pushtypes.OutOfStoreMessageEnvelope, groupPK crypto.PubKey) (*protocoltypes.OutOfStoreMessage, error) {
- nonce, err := cryptoutil.NonceSliceToArray(env.Nonce)
- if err != nil {
- return nil, errcode.ErrInvalidInput.Wrap(err)
- }
-
- g, err := gd.Get(ctx, groupPK)
- if err != nil {
- return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("unable to find group, err: %w", err))
- }
-
- secret := cryptoutil.GetSharedSecret(g)
-
- data, ok := secretbox.Open(nil, env.Box, nonce, secret)
- if !ok {
- return nil, errcode.ErrCryptoDecrypt
- }
-
- outOfStoreMessage := &protocoltypes.OutOfStoreMessage{}
- if err := outOfStoreMessage.Unmarshal(data); err != nil {
- return nil, errcode.ErrDeserialization.Wrap(err)
- }
-
- return outOfStoreMessage, nil
-}
-
-func (s *pushHandler) getServerPushPubKey(ctx context.Context) (*[cryptoutil.KeySize]byte, error) {
- serverBytes, err := s.accountCache.Get(ctx, ds.NewKey(datastoreutil.AccountCacheDatastorePushServerPK))
- if err != nil {
- return nil, errcode.ErrInternal.Wrap(fmt.Errorf("missing push server data: %w", err))
- }
-
- if len(serverBytes) == 0 {
- return nil, errcode.ErrInternal.Wrap(fmt.Errorf("got an empty push server data"))
- }
-
- server := &protocoltypes.PushServer{}
- if err := server.Unmarshal(serverBytes); err != nil {
- return nil, errcode.ErrDeserialization.Wrap(fmt.Errorf("unable to deserialize push server data: %w", err))
- }
-
- if l := len(server.ServerKey); l != cryptoutil.KeySize {
- return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("invalid push pk size, expected %d bytes, got %d", cryptoutil.KeySize, l))
- }
-
- out := [cryptoutil.KeySize]byte{}
- copy(out[:], server.ServerKey)
-
- return &out, nil
-}
-
-type pushHandlerClient struct {
- serviceClient protocoltypes.ProtocolServiceClient
-}
-
-func (p *pushHandlerClient) PushReceive(ctx context.Context, payload []byte) (*protocoltypes.PushReceive_Reply, error) {
- ctx, cancel := context.WithTimeout(ctx, time.Second*5)
- defer cancel()
-
- return p.serviceClient.PushReceive(ctx, &protocoltypes.PushReceive_Request{Payload: payload})
-}
-
-func (p *pushHandlerClient) PushPK() *[32]byte {
- // TODO: not supported in client mode
- return nil
-}
-
-func (p *pushHandlerClient) SetPushSK(i *[32]byte) {
- // TODO: not supported in client mode
-}
-
-func (p *pushHandlerClient) UpdatePushServer(ctx context.Context, server *protocoltypes.PushServer) error {
- ctx, cancel := context.WithTimeout(ctx, time.Second*5)
- defer cancel()
-
- _, err := p.serviceClient.PushSetServer(ctx, &protocoltypes.PushSetServer_Request{Server: server})
-
- return err
-}
-
-func NewPushHandlerViaProtocol(ctx context.Context, serviceClient protocoltypes.ProtocolServiceClient) PushHandler {
- return &pushHandlerClient{serviceClient: serviceClient}
-}
-
-func DecryptPushDataFromServer(data []byte, serverPK, ownSK *[32]byte) ([]byte, error) {
- if serverPK == nil {
- return nil, errcode.ErrPushUnableToDecrypt.Wrap(fmt.Errorf("no push server public key provided"))
- }
-
- if ownSK == nil {
- return nil, errcode.ErrPushUnableToDecrypt.Wrap(fmt.Errorf("no push receiver secret key provided"))
- }
-
- pushEnv := &pushtypes.PushExposedData{}
- if err := pushEnv.Unmarshal(data); err != nil {
- return nil, errcode.ErrPushInvalidPayload.Wrap(err)
- }
-
- nonce, err := cryptoutil.NonceSliceToArray(pushEnv.Nonce)
- if err != nil {
- return nil, errcode.ErrPushInvalidPayload.Wrap(err)
- }
-
- msgBytes, ok := box.Open(nil, pushEnv.Box, nonce, serverPK, ownSK)
- if !ok {
- return nil, errcode.ErrPushUnableToDecrypt.Wrap(fmt.Errorf("box.Open failed"))
- }
-
- return msgBytes, nil
-}
diff --git a/pkg/cryptoutil/group.go b/pkg/cryptoutil/group.go
deleted file mode 100644
index 5cbcc4b1..00000000
--- a/pkg/cryptoutil/group.go
+++ /dev/null
@@ -1,85 +0,0 @@
-package cryptoutil
-
-import (
- "encoding/binary"
- "fmt"
- "io"
-
- "golang.org/x/crypto/hkdf"
- "golang.org/x/crypto/sha3"
-
- "berty.tech/weshnet/pkg/errcode"
-)
-
-const PushSecretNamespace = "push_secret_ref" // nolint:gosec
-
-type GroupWithSecret interface {
- GetPublicKey() []byte
- GetSecret() []byte
-}
-
-type GroupWithLinkKey interface {
- GroupWithSecret
- GetLinkKey() []byte
-}
-
-func ComputeLinkKey(publicKey, secret []byte) (*[KeySize]byte, error) {
- arr := [KeySize]byte{}
-
- kdf := hkdf.New(sha3.New256, secret, nil, publicKey)
- if _, err := io.ReadFull(kdf, arr[:]); err != nil {
- return nil, errcode.ErrStreamRead.Wrap(err)
- }
-
- return &arr, nil
-}
-
-func GetLinkKeyArray(m GroupWithLinkKey) (*[KeySize]byte, error) {
- if len(m.GetLinkKey()) == KeySize {
- arr := [KeySize]byte{}
-
- for i, c := range m.GetLinkKey() {
- arr[i] = c
- }
-
- return &arr, nil
- }
-
- return ComputeLinkKey(m.GetPublicKey(), m.GetSecret())
-}
-
-func GetSharedSecret(m GroupWithLinkKey) *[KeySize]byte {
- sharedSecret := [KeySize]byte{}
- copy(sharedSecret[:], m.GetSecret())
-
- return &sharedSecret
-}
-
-func GetGroupPushSecret(m GroupWithSecret) ([]byte, error) {
- if len(m.GetSecret()) == 0 {
- return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("no secret known for group"))
- }
-
- arr := [KeySize]byte{}
-
- kdf := hkdf.New(sha3.New256, m.GetSecret(), nil, []byte(PushSecretNamespace))
- if _, err := io.ReadFull(kdf, arr[:]); err != nil {
- return nil, errcode.ErrStreamRead.Wrap(err)
- }
-
- return arr[:], nil
-}
-
-func CreatePushGroupReference(sender []byte, counter uint64, secret []byte) ([]byte, error) {
- arr := [KeySize]byte{}
-
- buf := make([]byte, 8)
- binary.BigEndian.PutUint64(buf, counter)
-
- kdf := hkdf.New(sha3.New256, secret, nil, append(sender, buf...))
- if _, err := io.ReadFull(kdf, arr[:]); err != nil {
- return nil, errcode.ErrStreamRead.Wrap(err)
- }
-
- return arr[:], nil
-}
diff --git a/pkg/cryptoutil/group_store.go b/pkg/cryptoutil/group_store.go
deleted file mode 100644
index 202fe1a0..00000000
--- a/pkg/cryptoutil/group_store.go
+++ /dev/null
@@ -1,213 +0,0 @@
-package cryptoutil
-
-import (
- "context"
- "crypto/ed25519"
- "crypto/sha256"
- "encoding/base64"
- "fmt"
- "io"
- "io/ioutil"
-
- "github.com/ipfs/go-datastore"
- "github.com/libp2p/go-libp2p/core/crypto"
- "golang.org/x/crypto/hkdf"
-
- "berty.tech/weshnet/internal/datastoreutil"
- "berty.tech/weshnet/pkg/errcode"
- "berty.tech/weshnet/pkg/protocoltypes"
-)
-
-const NamespaceGroupDatastore = "account_groups_datastore"
-
-type GroupDatastore struct {
- store datastore.Datastore
-}
-
-type GroupDatastoreReadOnly interface {
- Has(ctx context.Context, key crypto.PubKey) (bool, error)
- Get(ctx context.Context, key crypto.PubKey) (*protocoltypes.Group, error)
-}
-
-func (gd *GroupDatastore) key(key []byte) datastore.Key {
- return datastore.NewKey(base64.RawURLEncoding.EncodeToString(key))
-}
-
-func (gd *GroupDatastore) Has(ctx context.Context, key crypto.PubKey) (bool, error) {
- keyBytes, err := key.Raw()
- if err != nil {
- return false, errcode.ErrSerialization.Wrap(err)
- }
-
- return gd.store.Has(ctx, gd.key(keyBytes))
-}
-
-func (gd *GroupDatastore) Get(ctx context.Context, key crypto.PubKey) (*protocoltypes.Group, error) {
- keyBytes, err := key.Raw()
- if err != nil {
- return nil, errcode.ErrSerialization.Wrap(err)
- }
-
- data, err := gd.store.Get(ctx, gd.key(keyBytes))
- if err != nil {
- return nil, errcode.ErrMissingMapKey.Wrap(err)
- }
-
- g := &protocoltypes.Group{}
- if err := g.Unmarshal(data); err != nil {
- return nil, errcode.ErrDeserialization.Wrap(err)
- }
-
- return g, nil
-}
-
-func (gd *GroupDatastore) Put(ctx context.Context, g *protocoltypes.Group) error {
- pk, err := g.GetPubKey()
- if err != nil {
- return errcode.ErrInvalidInput.Wrap(err)
- }
-
- if ok, err := gd.Has(ctx, pk); err != nil {
- return errcode.ErrInvalidInput.Wrap(err)
- } else if ok {
- return nil
- }
-
- data, err := g.Marshal()
- if err != nil {
- return errcode.ErrSerialization.Wrap(err)
- }
-
- if err := gd.store.Put(ctx, gd.key(g.PublicKey), data); err != nil {
- return errcode.ErrKeystorePut.Wrap(err)
- }
-
- return nil
-}
-
-func (gd *GroupDatastore) Delete(ctx context.Context, pk crypto.PubKey) error {
- pkBytes, err := pk.Raw()
- if err != nil {
- return errcode.ErrSerialization.Wrap(err)
- }
-
- return gd.store.Delete(ctx, gd.key(pkBytes))
-}
-
-func (gd *GroupDatastore) PutForContactPK(ctx context.Context, pk crypto.PubKey, deviceKeystore DeviceKeystore) error {
- if deviceKeystore == nil {
- return errcode.ErrInvalidInput.Wrap(fmt.Errorf("missing device keystore"))
- }
-
- sk, err := deviceKeystore.ContactGroupPrivKey(pk)
- if err != nil {
- return errcode.ErrCryptoKeyGeneration.Wrap(err)
- }
-
- g, err := GetGroupForContact(sk)
- if err != nil {
- return errcode.ErrOrbitDBOpen.Wrap(err)
- }
-
- if err := gd.Put(ctx, g); err != nil {
- return errcode.ErrInternal.Wrap(err)
- }
-
- return nil
-}
-
-func NewGroupDatastore(ds datastore.Datastore) (*GroupDatastore, error) {
- if ds == nil {
- return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("a datastore is expected"))
- }
-
- return &GroupDatastore{
- store: datastoreutil.NewNamespacedDatastore(ds, datastore.NewKey(NamespaceGroupDatastore)),
- }, nil
-}
-
-func GetGroupForContact(contactPairSK crypto.PrivKey) (*protocoltypes.Group, error) {
- groupSK, groupSecretSK, err := GetKeysForGroupOfContact(contactPairSK)
- if err != nil {
- return nil, errcode.ErrCryptoKeyGeneration.Wrap(err)
- }
- pubBytes, err := groupSK.GetPublic().Raw()
- if err != nil {
- return nil, errcode.ErrSerialization.Wrap(err)
- }
-
- signingBytes, err := SeedFromEd25519PrivateKey(groupSecretSK)
- if err != nil {
- return nil, errcode.ErrSerialization.Wrap(err)
- }
-
- return &protocoltypes.Group{
- PublicKey: pubBytes,
- Secret: signingBytes,
- SecretSig: nil,
- GroupType: protocoltypes.GroupTypeContact,
- }, nil
-}
-
-func GetGroupForAccount(priv, signing crypto.PrivKey) (*protocoltypes.Group, error) {
- pubBytes, err := priv.GetPublic().Raw()
- if err != nil {
- return nil, errcode.ErrSerialization.Wrap(err)
- }
-
- signingBytes, err := SeedFromEd25519PrivateKey(signing)
- if err != nil {
- return nil, errcode.ErrSerialization.Wrap(err)
- }
-
- return &protocoltypes.Group{
- PublicKey: pubBytes,
- Secret: signingBytes,
- SecretSig: nil,
- GroupType: protocoltypes.GroupTypeAccount,
- }, nil
-}
-
-func GetKeysForGroupOfContact(contactPairSK crypto.PrivKey) (crypto.PrivKey, crypto.PrivKey, error) {
- // Salt length must be equal to hash length (64 bytes for sha256)
- hash := sha256.New
-
- ck, err := contactPairSK.Raw()
- if err != nil {
- return nil, nil, errcode.ErrSerialization.Wrap(err)
- }
-
- // Generate Pseudo Random Key using ck as IKM and salt
- prk := hkdf.Extract(hash, ck, nil)
- if len(prk) == 0 {
- return nil, nil, errcode.ErrInternal
- }
-
- // Expand using extracted prk and groupID as info (kind of namespace)
- kdf := hkdf.Expand(hash, prk, nil)
-
- // Generate next KDF and message keys
- groupSeed, err := ioutil.ReadAll(io.LimitReader(kdf, 32))
- if err != nil {
- return nil, nil, errcode.ErrCryptoKeyGeneration.Wrap(err)
- }
-
- groupSecretSeed, err := ioutil.ReadAll(io.LimitReader(kdf, 32))
- if err != nil {
- return nil, nil, errcode.ErrCryptoKeyGeneration.Wrap(err)
- }
-
- sk1 := ed25519.NewKeyFromSeed(groupSeed)
- groupSK, _, err := crypto.KeyPairFromStdKey(&sk1)
- if err != nil {
- return nil, nil, errcode.ErrCryptoKeyGeneration.Wrap(err)
- }
-
- sk2 := ed25519.NewKeyFromSeed(groupSecretSeed)
- groupSecretSK, _, err := crypto.KeyPairFromStdKey(&sk2)
- if err != nil {
- return nil, nil, errcode.ErrCryptoKeyGeneration.Wrap(err)
- }
-
- return groupSK, groupSecretSK, nil
-}
diff --git a/pkg/cryptoutil/keystore_device.go b/pkg/cryptoutil/keystore_device.go
deleted file mode 100644
index ec08db79..00000000
--- a/pkg/cryptoutil/keystore_device.go
+++ /dev/null
@@ -1,327 +0,0 @@
-package cryptoutil
-
-import (
- "crypto/ed25519"
- crand "crypto/rand"
- "encoding/hex"
- "fmt"
- "strings"
- "sync"
-
- "github.com/aead/ecdh"
- keystore "github.com/ipfs/go-ipfs-keystore"
- "github.com/libp2p/go-libp2p/core/crypto"
- "go.uber.org/zap"
-
- "berty.tech/weshnet/pkg/errcode"
- "berty.tech/weshnet/pkg/protocoltypes"
-)
-
-type DeviceKeystore interface {
- AccountPrivKey() (crypto.PrivKey, error)
- AccountProofPrivKey() (crypto.PrivKey, error)
- DevicePrivKey() (crypto.PrivKey, error)
- ContactGroupPrivKey(pk crypto.PubKey) (crypto.PrivKey, error)
- MemberDeviceForGroup(g *protocoltypes.Group) (*OwnMemberDevice, error)
- RestoreAccountKeys(accountKey crypto.PrivKey, accountProofKey crypto.PrivKey) error
-}
-
-type deviceKeystore struct {
- ks keystore.Keystore
- mu sync.Mutex
- logger *zap.Logger
-}
-
-type DeviceKeystoreOpts struct {
- Logger *zap.Logger
-}
-
-const (
- keyAccount = "accountSK"
- keyAccountProof = "accountProofSK"
- keyDevice = "deviceSK"
- keyMemberDevice = "memberDeviceSK"
- keyMember = "memberSK"
- keyContactGroup = "contactGroupSK"
-)
-
-// AccountPrivKey returns the private key associated with the current account
-func (a *deviceKeystore) AccountPrivKey() (crypto.PrivKey, error) {
- a.mu.Lock()
- defer a.mu.Unlock()
-
- return a.getOrGenerateNamedKey(keyAccount)
-}
-
-// AccountProofPrivKey returns the private key associated with the current account
-func (a *deviceKeystore) AccountProofPrivKey() (crypto.PrivKey, error) {
- a.mu.Lock()
- defer a.mu.Unlock()
-
- return a.getOrGenerateNamedKey(keyAccountProof)
-}
-
-// DevicePrivKey returns the current Device private key
-func (a *deviceKeystore) DevicePrivKey() (crypto.PrivKey, error) {
- a.mu.Lock()
- defer a.mu.Unlock()
-
- return a.getOrGenerateNamedKey(keyDevice)
-}
-
-// ContactGroupPrivKey retrieves the deviceKeystore signing key associated with the supplied contact pub key
-func (a *deviceKeystore) ContactGroupPrivKey(pk crypto.PubKey) (crypto.PrivKey, error) {
- accountSK, err := a.AccountPrivKey()
- if err != nil {
- return nil, err
- }
-
- return a.getOrComputeECDH(keyContactGroup, pk, accountSK)
-}
-
-// memberDeviceForMultiMemberGroup retrieves the Device signing key associated with the supplied group pub key
-func (a *deviceKeystore) memberDeviceForMultiMemberGroup(groupPK crypto.PubKey) (*OwnMemberDevice, error) {
- memberSK, err := a.getOrComputeDeviceKeyForGroupMember(groupPK)
- if err != nil {
- return nil, err
- }
-
- deviceSK, err := a.getOrGenerateDeviceKeyForGroupDevice(groupPK)
- if err != nil {
- return nil, err
- }
-
- return &OwnMemberDevice{
- member: memberSK,
- device: deviceSK,
- }, nil
-}
-
-func (a *deviceKeystore) MemberDeviceForGroup(g *protocoltypes.Group) (*OwnMemberDevice, error) {
- pk, err := g.GetPubKey()
- if err != nil {
- return nil, errcode.ErrInvalidInput.Wrap(err)
- }
-
- switch g.GroupType {
- case protocoltypes.GroupTypeAccount, protocoltypes.GroupTypeContact:
- memberSK, err := a.AccountPrivKey()
- if err != nil {
- return nil, err
- }
-
- deviceSK, err := a.DevicePrivKey()
- if err != nil {
- return nil, err
- }
-
- return &OwnMemberDevice{
- member: memberSK,
- device: deviceSK,
- }, nil
-
- case protocoltypes.GroupTypeMultiMember:
- return a.memberDeviceForMultiMemberGroup(pk)
- }
-
- return nil, errcode.ErrInvalidInput
-}
-
-func (a *deviceKeystore) getOrGenerateNamedKey(name string) (crypto.PrivKey, error) {
- sk, err := a.ks.Get(name)
- if err == nil {
- return sk, nil
- } else if err.Error() != keystore.ErrNoSuchKey.Error() {
- return nil, err
- }
-
- sk, _, err = crypto.GenerateEd25519Key(crand.Reader)
- if err != nil {
- return nil, err
- }
-
- if err := a.ks.Put(name, sk); err != nil {
- return nil, err
- }
-
- return sk, nil
-}
-
-func (a *deviceKeystore) getOrGenerateDeviceKeyForGroupDevice(pk crypto.PubKey) (crypto.PrivKey, error) {
- a.mu.Lock()
- defer a.mu.Unlock()
-
- groupPKRaw, err := pk.Raw()
- if err != nil {
- return nil, err
- }
-
- name := strings.Join([]string{keyMemberDevice, hex.EncodeToString(groupPKRaw)}, "_")
-
- return a.getOrGenerateNamedKey(name)
-}
-
-func (a *deviceKeystore) getOrComputeECDH(nameSpace string, pk crypto.PubKey, ownSK crypto.PrivKey) (crypto.PrivKey, error) {
- a.mu.Lock()
- defer a.mu.Unlock()
-
- pkRaw, err := pk.Raw()
- if err != nil {
- return nil, err
- }
-
- name := strings.Join([]string{nameSpace, hex.EncodeToString(pkRaw)}, "_")
-
- sk, err := a.ks.Get(name)
- if err == nil {
- return sk, nil
- } else if err.Error() != keystore.ErrNoSuchKey.Error() {
- return nil, err
- }
-
- skB, pkB, err := EdwardsToMontgomery(ownSK, pk)
- if err != nil {
- return nil, err
- }
-
- secret := ecdh.X25519().ComputeSecret(skB, pkB)
- groupSK := ed25519.NewKeyFromSeed(secret)
-
- sk, _, err = crypto.KeyPairFromStdKey(&groupSK)
- if err != nil {
- return nil, err
- }
-
- if err := a.ks.Put(name, sk); err != nil {
- return nil, err
- }
-
- return sk, nil
-}
-
-func (a *deviceKeystore) getOrComputeDeviceKeyForGroupMember(pk crypto.PubKey) (crypto.PrivKey, error) {
- accountProofSK, err := a.AccountProofPrivKey()
- if err != nil {
- return nil, err
- }
-
- return a.getOrComputeECDH(keyMember, pk, accountProofSK)
-}
-
-func (a *deviceKeystore) RestoreAccountKeys(sk crypto.PrivKey, proofSK crypto.PrivKey) error {
- if sk == nil {
- return errcode.ErrInvalidInput.Wrap(fmt.Errorf("missing account key"))
- }
-
- if proofSK == nil {
- return errcode.ErrInvalidInput.Wrap(fmt.Errorf("missing account proof key"))
- }
-
- ok, err := a.ks.Has(keyAccount)
- if err != nil {
- return err
- }
-
- if ok {
- return errcode.ErrInvalidInput.Wrap(fmt.Errorf("an account key is already set in this keystore"))
- }
-
- ok, err = a.ks.Has(keyAccountProof)
- if err != nil {
- return err
- }
-
- if ok {
- return errcode.ErrInvalidInput.Wrap(fmt.Errorf("an account proof key is already set in this keystore"))
- }
-
- if err := a.ks.Put(keyAccount, sk); err != nil {
- return err
- }
-
- if err := a.ks.Put(keyAccountProof, proofSK); err != nil {
- return err
- }
-
- return nil
-}
-
-// OwnMemberDevice is own local Device part of a group
-type OwnMemberDevice struct {
- member crypto.PrivKey
- device crypto.PrivKey
-}
-
-func (d *OwnMemberDevice) PrivateMember() crypto.PrivKey {
- return d.member
-}
-
-func (d *OwnMemberDevice) PrivateDevice() crypto.PrivKey {
- return d.device
-}
-
-func (d *OwnMemberDevice) Public() *MemberDevice {
- return &MemberDevice{
- Member: d.member.GetPublic(),
- Device: d.device.GetPublic(),
- }
-}
-
-func NewOwnMemberDevice(member crypto.PrivKey, device crypto.PrivKey) *OwnMemberDevice {
- return &OwnMemberDevice{
- member: member,
- device: device,
- }
-}
-
-// MemberDevice is a remote Device part of a group
-type MemberDevice struct {
- Member crypto.PubKey
- Device crypto.PubKey
-}
-
-func NewDeviceSecret() (*protocoltypes.DeviceSecret, error) {
- chainKey := make([]byte, 32)
- _, err := crand.Read(chainKey)
- if err != nil {
- return nil, errcode.ErrCryptoRandomGeneration.Wrap(err)
- }
-
- return &protocoltypes.DeviceSecret{
- ChainKey: chainKey,
- Counter: 0,
- }, nil
-}
-
-// NewDeviceKeystore creates a new deviceKeystore instance, if the keystore does not hold an deviceKeystore key, one will be created when required
-func NewDeviceKeystore(ks keystore.Keystore, opts *DeviceKeystoreOpts) DeviceKeystore {
- if opts == nil {
- opts = &DeviceKeystoreOpts{}
- }
-
- if opts.Logger == nil {
- opts.Logger = zap.NewNop()
- }
-
- return &deviceKeystore{
- ks: ks,
- logger: opts.Logger,
- }
-}
-
-// NewWithExistingKeys creates a new deviceKeystore instance and registers the supplied secret key, useful when migrating deviceKeystore to another device
-func NewWithExistingKeys(ks keystore.Keystore, sk crypto.PrivKey, proofSK crypto.PrivKey) (DeviceKeystore, error) {
- acc := &deviceKeystore{
- ks: ks,
- }
-
- if err := ks.Put(keyAccount, sk); err != nil {
- return nil, err
- }
-
- if err := ks.Put(keyAccountProof, proofSK); err != nil {
- return nil, err
- }
-
- return acc, nil
-}
diff --git a/pkg/cryptoutil/keystore_device_test.go b/pkg/cryptoutil/keystore_device_test.go
deleted file mode 100644
index b906581a..00000000
--- a/pkg/cryptoutil/keystore_device_test.go
+++ /dev/null
@@ -1,175 +0,0 @@
-package cryptoutil_test
-
-import (
- "testing"
-
- keystore "github.com/ipfs/go-ipfs-keystore"
- "github.com/stretchr/testify/assert"
-
- "berty.tech/weshnet"
- "berty.tech/weshnet/pkg/cryptoutil"
-)
-
-func Test_New_AccountPrivKey_AccountProofPrivKey(t *testing.T) {
- ks := keystore.NewMemKeystore()
- acc := cryptoutil.NewDeviceKeystore(ks, nil)
- assert.NotNil(t, acc)
-
- sk1, err := acc.AccountPrivKey()
- assert.NoError(t, err)
- assert.NotNil(t, sk1)
-
- sk2, err := acc.AccountPrivKey()
- assert.NoError(t, err)
- assert.NotNil(t, sk2)
-
- assert.True(t, sk1.Equals(sk2))
-
- skProof1, err := acc.AccountProofPrivKey()
- assert.NoError(t, err)
- assert.NotNil(t, skProof1)
-
- skProof2, err := acc.AccountProofPrivKey()
- assert.NoError(t, err)
- assert.NotNil(t, skProof2)
-
- assert.True(t, skProof1.Equals(skProof2))
- assert.False(t, sk1.Equals(skProof1))
- assert.False(t, sk1.Equals(skProof2))
- assert.False(t, sk2.Equals(skProof1))
- assert.False(t, sk2.Equals(skProof2))
-}
-
-func Test_NewWithExistingKeys_AccountPrivKey_AccountProofPrivKey(t *testing.T) {
- ks1 := keystore.NewMemKeystore()
- acc1 := cryptoutil.NewDeviceKeystore(ks1, nil)
-
- sk1, err := acc1.AccountPrivKey()
- assert.NoError(t, err)
- assert.NotNil(t, sk1)
-
- skProof1, err := acc1.AccountProofPrivKey()
- assert.NoError(t, err)
- assert.NotNil(t, skProof1)
-
- ks2 := keystore.NewMemKeystore()
- acc2, err := cryptoutil.NewWithExistingKeys(ks2, sk1, skProof1)
- assert.NoError(t, err)
- assert.NotNil(t, acc2)
-
- sk2, err := acc2.AccountPrivKey()
- assert.NoError(t, err)
- assert.NotNil(t, sk2)
-
- assert.True(t, sk1.Equals(sk2))
-
- skProof2, err := acc2.AccountProofPrivKey()
- assert.NoError(t, err)
- assert.NotNil(t, skProof2)
-
- assert.True(t, skProof1.Equals(skProof2))
- assert.False(t, sk1.Equals(skProof1))
- assert.False(t, sk1.Equals(skProof2))
- assert.False(t, sk2.Equals(skProof1))
- assert.False(t, sk2.Equals(skProof2))
-}
-
-func Test_DevicePrivKey(t *testing.T) {
- ks1 := keystore.NewMemKeystore()
- acc1 := cryptoutil.NewDeviceKeystore(ks1, nil)
-
- sk1, err := acc1.AccountPrivKey()
- assert.NoError(t, err)
- assert.NotNil(t, sk1)
-
- skProof1, err := acc1.AccountProofPrivKey()
- assert.NoError(t, err)
- assert.NotNil(t, skProof1)
-
- ks2 := keystore.NewMemKeystore()
- acc2, err := cryptoutil.NewWithExistingKeys(ks2, sk1, skProof1)
- assert.NoError(t, err)
- assert.NotNil(t, acc2)
-
- dev1, err := acc1.DevicePrivKey()
- assert.NoError(t, err)
- assert.NotNil(t, dev1)
-
- dev2, err := acc2.DevicePrivKey()
- assert.NoError(t, err)
- assert.NotNil(t, dev2)
-
- assert.False(t, dev1.Equals(dev2))
-}
-
-func Test_ContactGroupPrivKey(t *testing.T) {
- ks1 := keystore.NewMemKeystore()
- acc1 := cryptoutil.NewDeviceKeystore(ks1, nil)
-
- sk1, err := acc1.AccountPrivKey()
- assert.NoError(t, err)
- assert.NotNil(t, sk1)
-
- ks2 := keystore.NewMemKeystore()
- acc2 := cryptoutil.NewDeviceKeystore(ks2, nil)
-
- sk2, err := acc2.AccountPrivKey()
- assert.NoError(t, err)
- assert.NotNil(t, sk2)
-
- skGrp1, err := acc1.ContactGroupPrivKey(sk2.GetPublic())
- assert.NoError(t, err)
-
- skGrp2, err := acc2.ContactGroupPrivKey(sk1.GetPublic())
- assert.NoError(t, err)
-
- assert.True(t, skGrp1.Equals(skGrp2))
-}
-
-func Test_MemberDeviceForGroup_account(t *testing.T) {
-}
-
-func Test_MemberDeviceForGroup_contact(t *testing.T) {
-}
-
-func Test_MemberDeviceForGroup_multimember(t *testing.T) {
- ks1 := keystore.NewMemKeystore()
- acc1 := cryptoutil.NewDeviceKeystore(ks1, nil)
-
- sk1, err := acc1.AccountPrivKey()
- assert.NoError(t, err)
- assert.NotNil(t, sk1)
-
- skProof1, err := acc1.AccountProofPrivKey()
- assert.NoError(t, err)
- assert.NotNil(t, skProof1)
-
- ks2 := keystore.NewMemKeystore()
- acc2, err := cryptoutil.NewWithExistingKeys(ks2, sk1, skProof1)
- assert.NoError(t, err)
- assert.NotNil(t, acc2)
-
- g, _, err := weshnet.NewGroupMultiMember()
- assert.NoError(t, err)
-
- omd1, err := acc1.MemberDeviceForGroup(g)
- assert.NoError(t, err)
-
- omd2, err := acc2.MemberDeviceForGroup(g)
- assert.NoError(t, err)
-
- omd1MB, err := omd1.PrivateMember().Raw()
- assert.NoError(t, err)
-
- omd2MB, err := omd2.PrivateMember().Raw()
- assert.NoError(t, err)
-
- omd1DB, err := omd1.PrivateDevice().Raw()
- assert.NoError(t, err)
-
- omd2DB, err := omd2.PrivateDevice().Raw()
- assert.NoError(t, err)
-
- assert.Equal(t, omd1MB, omd2MB)
- assert.NotEqual(t, omd1DB, omd2DB)
-}
diff --git a/pkg/cryptoutil/keystore_message.go b/pkg/cryptoutil/keystore_message.go
deleted file mode 100644
index 5526fc6c..00000000
--- a/pkg/cryptoutil/keystore_message.go
+++ /dev/null
@@ -1,918 +0,0 @@
-package cryptoutil
-
-import (
- "context"
- "encoding/base64"
- "fmt"
- "sync"
-
- "github.com/ipfs/go-cid"
- "github.com/ipfs/go-datastore"
- dssync "github.com/ipfs/go-datastore/sync"
- "github.com/libp2p/go-libp2p/core/crypto"
- "go.uber.org/zap"
- "golang.org/x/crypto/nacl/secretbox"
-
- "berty.tech/weshnet/pkg/errcode"
- "berty.tech/weshnet/pkg/logutil"
- "berty.tech/weshnet/pkg/protocoltypes"
-)
-
-const precomputePushRefsCount = 100
-
-// MessageKeystore is a key-value store for storing values related to message
-// opening. It has the following namespaces:
-// - `chainKeyForDeviceOnGroup`:
-// Storing the current state of a device chain key for a given group.
-// It contains the secret used to derive the next value of the chain key
-// and used to generate a message key for the message at `counter` value,
-// then put in the `precomputedMessageKeys` namespace.
-// - `precomputedMessageKeys`:
-// Storing precomputed message keys for a given group, device and message
-// counter. As the chain key stored has already been derived, these
-// message keys need to be computed beforehand. The corresponding message
-// can then be decrypted via a quick lookup.
-// - `messageKeyForCIDs`:
-// Containing the message key for a given message CID once the
-// corresponding message has been decrypted.
-// - `outOfStoreGroupHint`:
-// Keys are a HMAC value associated to a group public key. It is used when
-// receiving an out-of-store message (e.g. a push notification) to
-// identify the group on which the message belongs, which can then
-// be decrypted.
-type MessageKeystore struct {
- lock sync.Mutex
- preComputedKeysCount int
- store *dssync.MutexDatastore
- logger *zap.Logger
-}
-
-type DecryptInfo struct {
- NewlyDecrypted bool
- MK *[32]byte
- Cid cid.Cid
-}
-
-// GetDeviceChainKey returns the device secret for the given group and device.
-func (m *MessageKeystore) GetDeviceChainKey(ctx context.Context, groupPK, pk crypto.PubKey) (*protocoltypes.DeviceSecret, error) {
- if m == nil {
- return nil, errcode.ErrInvalidInput
- }
-
- pkB, err := pk.Raw()
- if err != nil {
- return nil, errcode.ErrSerialization.Wrap(err)
- }
-
- groupRaw, err := groupPK.Raw()
- if err != nil {
- return nil, errcode.ErrSerialization.Wrap(err)
- }
-
- key := idForCurrentCK(groupRaw, pkB)
-
- dsBytes, err := m.store.Get(ctx, key)
- if err == datastore.ErrNotFound {
- return nil, errcode.ErrMissingInput.Wrap(err)
- } else if err != nil {
- return nil, errcode.ErrMessageKeyPersistenceGet.Wrap(err)
- }
-
- ds := &protocoltypes.DeviceSecret{}
- if err := ds.Unmarshal(dsBytes); err != nil {
- return nil, errcode.ErrInvalidInput
- }
-
- return ds, nil
-}
-
-// HasSecretForRawDevicePK returns true if the device secret is known for the given group and device.
-func (m *MessageKeystore) HasSecretForRawDevicePK(ctx context.Context, groupPK, devicePK []byte) (has bool) {
- if m == nil {
- return false
- }
-
- key := idForCurrentCK(groupPK, devicePK)
- has, _ = m.store.Has(ctx, key)
- return
-}
-
-// delPrecomputedKey deletes the message key in the cache namespace for the given group, device and counter.
-func (m *MessageKeystore) delPrecomputedKey(ctx context.Context, groupPK, device crypto.PubKey, counter uint64) error {
- if m == nil {
- return errcode.ErrInvalidInput
- }
-
- deviceRaw, err := device.Raw()
- if err != nil {
- return errcode.ErrSerialization.Wrap(err)
- }
-
- groupRaw, err := groupPK.Raw()
- if err != nil {
- return errcode.ErrSerialization.Wrap(err)
- }
-
- id := idForPrecomputeMK(groupRaw, deviceRaw, counter)
- if err := m.store.Delete(ctx, id); err != nil {
- return errcode.ErrMessageKeyPersistencePut.Wrap(err)
- }
-
- return nil
-}
-
-// PostDecryptActions is called after a message has been decrypted.
-// It saves the message key from the cache namespace to find it quickly on subsequent read operations.
-// It derives the chain key in the cache namespace.
-func (m *MessageKeystore) PostDecryptActions(ctx context.Context, di *DecryptInfo, g *protocoltypes.Group, ownPK crypto.PubKey, headers *protocoltypes.MessageHeaders) error {
- if m == nil {
- return errcode.ErrInvalidInput
- }
-
- // Message was newly decrypted, we can save the message key and derive
- // future keys if necessary.
- if di == nil || !di.NewlyDecrypted {
- return nil
- }
-
- var (
- ds *protocoltypes.DeviceSecret
- err error
- )
-
- pk, err := crypto.UnmarshalEd25519PublicKey(headers.DevicePK)
- if err != nil {
- return errcode.ErrDeserialization.Wrap(err)
- }
-
- groupPK, err := g.GetPubKey()
- if err != nil {
- return errcode.ErrDeserialization.Wrap(err)
- }
-
- if err = m.putKeyForCID(ctx, di.Cid, di.MK); err != nil {
- return errcode.ErrInternal.Wrap(err)
- }
-
- if err = m.delPrecomputedKey(ctx, groupPK, pk, headers.Counter); err != nil {
- return errcode.ErrInternal.Wrap(err)
- }
-
- if ds, err = m.preComputeNextKey(ctx, groupPK, pk); err != nil {
- return errcode.ErrInternal.Wrap(err)
- }
-
- // If the message was not emitted by the current Device we might need
- // to update the current chain key
- if ownPK == nil || !ownPK.Equals(pk) {
- if err = m.updateCurrentKey(ctx, groupPK, pk, ds); err != nil {
- return errcode.ErrInternal.Wrap(err)
- }
- }
-
- return nil
-}
-
-// GetDeviceSecret returns the device secret for the current device on a given group.
-// If the chain key has not been created yet, it will be generated and registered.
-func (m *MessageKeystore) GetDeviceSecret(ctx context.Context, g *protocoltypes.Group, acc DeviceKeystore) (*protocoltypes.DeviceSecret, error) {
- if m == nil {
- return nil, errcode.ErrInvalidInput
- }
-
- md, err := acc.MemberDeviceForGroup(g)
- if err != nil {
- return nil, errcode.ErrInternal.Wrap(err)
- }
-
- groupPK, err := g.GetPubKey()
- if err != nil {
- return nil, errcode.ErrDeserialization.Wrap(err)
- }
-
- ds, err := m.GetDeviceChainKey(ctx, groupPK, md.device.GetPublic())
- if errcode.Is(err, errcode.ErrMissingInput) {
- // If secret does not exist, create it
- ds, err := NewDeviceSecret()
- if err != nil {
- return nil, errcode.ErrCryptoKeyGeneration.Wrap(err)
- }
-
- if err = m.registerChainKey(ctx, g, md.device.GetPublic(), ds, true); err != nil {
- return nil, errcode.ErrMessageKeyPersistencePut.Wrap(err)
- }
-
- return ds, nil
- }
- if err != nil {
- return nil, errcode.ErrMessageKeyPersistenceGet.Wrap(err)
- }
-
- return ds, nil
-}
-
-// RegisterChainKey registers a device secret for the given group and device.
-// If the device secret is not from the current device, the function will
-// precompute and store in the cache namespace the next message keys.
-// It is the exported version of registerChainKey.
-func (m *MessageKeystore) RegisterChainKey(ctx context.Context, g *protocoltypes.Group, devicePK crypto.PubKey, ds *protocoltypes.DeviceSecret, isOwnPK bool) error {
- if m == nil {
- return errcode.ErrInvalidInput
- }
-
- return m.registerChainKey(ctx, g, devicePK, ds, isOwnPK)
-}
-
-// registerChainKey registers a device secret for the given group and device.
-// If the device secret is not from the current device, the function will
-// precompute and store in the cache namespace the next message keys.
-func (m *MessageKeystore) registerChainKey(ctx context.Context, g *protocoltypes.Group, devicePK crypto.PubKey, ds *protocoltypes.DeviceSecret, isOwnPK bool) error {
- if m == nil {
- return errcode.ErrInvalidInput
- }
-
- groupPK, err := g.GetPubKey()
- if err != nil {
- return errcode.ErrDeserialization.Wrap(err)
- }
-
- if _, err := m.GetDeviceChainKey(ctx, groupPK, devicePK); err == nil {
- // Device is already registered, ignore it
- m.logger.Debug("device already registered in group",
- logutil.PrivateBinary("devicePK", logutil.CryptoKeyToBytes(devicePK)),
- logutil.PrivateBinary("groupPK", logutil.CryptoKeyToBytes(groupPK)),
- )
- return nil
- }
-
- m.logger.Debug("registering chain key",
- logutil.PrivateBinary("devicePK", logutil.CryptoKeyToBytes(devicePK)),
- logutil.PrivateBinary("groupPK", logutil.CryptoKeyToBytes(groupPK)),
- )
-
- // If own Device store key as is, no need to precompute future keys
- if isOwnPK {
- if err := m.putDeviceChainKey(ctx, groupPK, devicePK, ds); err != nil {
- return errcode.ErrInternal.Wrap(err)
- }
-
- return nil
- }
-
- if ds, err = m.preComputeKeys(ctx, devicePK, groupPK, ds); err != nil {
- return errcode.ErrCryptoKeyGeneration.Wrap(err)
- }
-
- if err := m.putDeviceChainKey(ctx, groupPK, devicePK, ds); err != nil {
- return errcode.ErrInternal.Wrap(err)
- }
-
- devicePKBytes, err := devicePK.Raw()
- if err == nil {
- if err := m.UpdatePushGroupReferences(ctx, devicePKBytes, ds.Counter, g); err != nil {
- m.logger.Error("updating push group references failed", zap.Error(err))
- }
- }
-
- return nil
-}
-
-// preComputeKeys precomputes the next m.preComputedKeysCount keys for the given device and group and put them in the cache namespace.
-func (m *MessageKeystore) preComputeKeys(ctx context.Context, device crypto.PubKey, groupPK crypto.PubKey, ds *protocoltypes.DeviceSecret) (*protocoltypes.DeviceSecret, error) {
- if m == nil {
- return nil, errcode.ErrInvalidInput
- }
-
- ck := ds.ChainKey
- counter := ds.Counter
-
- groupPKBytes, err := groupPK.Raw()
- if err != nil {
- return nil, errcode.ErrSerialization.Wrap(err)
- }
-
- knownCK, err := m.GetDeviceChainKey(ctx, groupPK, device)
- if err != nil && !errcode.Is(err, errcode.ErrMissingInput) {
- return nil, errcode.ErrInternal.Wrap(err)
- }
-
- preComputedKeys := []computedKey{}
- for i := 0; i < m.GetPrecomputedKeyExpectedCount(); i++ {
- counter++
-
- knownMK, err := m.getPrecomputedKey(ctx, groupPK, device, counter)
- if err != nil && !errcode.Is(err, errcode.ErrMissingInput) {
- return nil, errcode.ErrInternal.Wrap(err)
- }
-
- // TODO: Salt?
- newCK, mk, err := deriveNextKeys(ck, nil, groupPKBytes)
- if err != nil {
- return nil, errcode.TODO.Wrap(err)
- }
-
- ck = newCK
-
- if knownMK != nil && knownCK != nil {
- if knownCK.Counter != counter-1 {
- continue
- }
- }
-
- preComputedKeys = append(preComputedKeys, computedKey{counter, &mk})
- }
-
- err = m.putPrecomputedKeys(ctx, groupPK, device, preComputedKeys...)
- if err != nil {
- return nil, errcode.TODO.Wrap(err)
- }
-
- return &protocoltypes.DeviceSecret{
- Counter: counter,
- ChainKey: ck,
- }, nil
-}
-
-// preComputeNextKey precomputes the next key for the given group and device and adds it to the cache namespace.
-func (m *MessageKeystore) preComputeNextKey(ctx context.Context, groupPK, devicePK crypto.PubKey) (*protocoltypes.DeviceSecret, error) {
- if m == nil || devicePK == nil {
- return nil, errcode.ErrInvalidInput
- }
-
- groupPKBytes, err := groupPK.Raw()
- if err != nil {
- return nil, errcode.ErrSerialization.Wrap(err)
- }
-
- ds, err := m.GetDeviceChainKey(ctx, groupPK, devicePK)
- if err != nil {
- return nil, errcode.ErrInternal.Wrap(err)
- }
-
- newCounter := ds.Counter + 1
-
- // TODO: Salt?
- newCK, mk, err := deriveNextKeys(ds.ChainKey, nil, groupPKBytes)
- if err != nil {
- return nil, errcode.TODO.Wrap(err)
- }
-
- err = m.putPrecomputedKeys(ctx, groupPK, devicePK, computedKey{newCounter, &mk})
- if err != nil {
- return nil, errcode.TODO.Wrap(err)
- }
-
- return &protocoltypes.DeviceSecret{
- Counter: newCounter,
- ChainKey: newCK,
- }, nil
-}
-
-// getPrecomputedKey returns the precomputed key put in the cache namespace for the given group and device at the given counter.
-func (m *MessageKeystore) getPrecomputedKey(ctx context.Context, groupPK, device crypto.PubKey, counter uint64) (*[32]byte, error) {
- if m == nil {
- return nil, errcode.ErrInvalidInput
- }
-
- deviceRaw, err := device.Raw()
- if err != nil {
- return nil, errcode.ErrSerialization.Wrap(err)
- }
-
- groupRaw, err := groupPK.Raw()
- if err != nil {
- return nil, errcode.ErrSerialization.Wrap(err)
- }
-
- id := idForPrecomputeMK(groupRaw, deviceRaw, counter)
-
- key, err := m.store.Get(ctx, id)
-
- if err == datastore.ErrNotFound {
- return nil, errcode.ErrMissingInput.Wrap(fmt.Errorf("key for message does not exist in datastore"))
- }
- if err != nil {
- return nil, errcode.ErrMessageKeyPersistenceGet.Wrap(err)
- }
-
- keyArray, err := KeySliceToArray(key)
- if err != nil {
- return nil, errcode.ErrSerialization
- }
-
- return keyArray, nil
-}
-
-// computedKey is a precomputed message key for a given counter used in the cache namespace.
-type computedKey struct {
- counter uint64
- mk *[32]byte
-}
-
-// putPrecomputedKeys puts the given precomputed keys in the cache namespace.
-// It will try to use a batch if the store supports it.
-func (m *MessageKeystore) putPrecomputedKeys(ctx context.Context, groupPK, device crypto.PubKey, preComputedKeys ...computedKey) error {
- if m == nil {
- return errcode.ErrInvalidInput
- }
-
- m.logger.Debug("putting precomputed keys", zap.Int("count", len(preComputedKeys)))
-
- if len(preComputedKeys) != 0 {
- deviceRaw, err := device.Raw()
- if err != nil {
- return errcode.ErrSerialization.Wrap(err)
- }
-
- groupRaw, err := groupPK.Raw()
- if err != nil {
- return errcode.ErrSerialization.Wrap(err)
- }
-
- batch, err := m.store.Batch(ctx)
- if err == datastore.ErrBatchUnsupported {
- for _, preComputedKey := range preComputedKeys {
- id := idForPrecomputeMK(groupRaw, deviceRaw, preComputedKey.counter)
-
- if err := m.store.Put(ctx, id, preComputedKey.mk[:]); err != nil {
- return errcode.ErrMessageKeyPersistencePut.Wrap(err)
- }
- }
-
- return nil
- } else if err != nil {
- return errcode.ErrMessageKeyPersistencePut.Wrap(err)
- }
-
- for _, preComputedKey := range preComputedKeys {
- id := idForPrecomputeMK(groupRaw, deviceRaw, preComputedKey.counter)
-
- if err := batch.Put(ctx, id, preComputedKey.mk[:]); err != nil {
- return errcode.ErrMessageKeyPersistencePut.Wrap(err)
- }
- }
-
- if err := batch.Commit(ctx); err != nil {
- return errcode.ErrMessageKeyPersistencePut.Wrap(err)
- }
- }
-
- return nil
-}
-
-// putKeyForCID puts the given message key in the datastore for the a specified CID.
-func (m *MessageKeystore) putKeyForCID(ctx context.Context, id cid.Cid, key *[32]byte) error {
- if m == nil {
- return errcode.ErrInvalidInput
- }
-
- if !id.Defined() {
- return nil
- }
-
- err := m.store.Put(ctx, idForMK(id), key[:])
- if err != nil {
- return errcode.ErrMessageKeyPersistencePut.Wrap(err)
- }
-
- return nil
-}
-
-// OpenEnvelopePayload opens the payload of a message envelope and returns the decrypted message in its EncryptedMessage form.
-// It also performs post decryption actions such as updating message key cache.
-func (m *MessageKeystore) OpenEnvelopePayload(
- ctx context.Context,
- env *protocoltypes.MessageEnvelope,
- headers *protocoltypes.MessageHeaders,
- g *protocoltypes.Group,
- ownPK crypto.PubKey,
- id cid.Cid,
-) (*protocoltypes.EncryptedMessage, error) {
- gPK, err := g.GetPubKey()
- if err != nil {
- return nil, errcode.ErrDeserialization.Wrap(err)
- }
-
- msgBytes, decryptInfo, err := m.OpenPayload(ctx, id, gPK, env.Message, headers)
- if err != nil {
- return nil, errcode.ErrCryptoDecryptPayload.Wrap(err)
- }
-
- if err := m.PostDecryptActions(ctx, decryptInfo, g, ownPK, headers); err != nil {
- return nil, errcode.TODO.Wrap(err)
- }
-
- var msg protocoltypes.EncryptedMessage
- err = msg.Unmarshal(msgBytes)
- if err != nil {
- return nil, errcode.ErrDeserialization.Wrap(err)
- }
-
- return &msg, nil
-}
-
-// OpenPayload opens the payload of a message envelope and returns the decrypted message.
-// It retrieves the message key from the keystore or the cache to decrypt the message.
-func (m *MessageKeystore) OpenPayload(ctx context.Context, id cid.Cid, groupPK crypto.PubKey, payload []byte, headers *protocoltypes.MessageHeaders) ([]byte, *DecryptInfo, error) {
- if m == nil {
- return nil, nil, errcode.ErrInvalidInput
- }
-
- var (
- err error
- di = &DecryptInfo{
- Cid: id,
- NewlyDecrypted: true,
- }
- pk crypto.PubKey
- )
-
- if di.MK, err = m.GetKeyForCID(ctx, id); err == nil {
- di.NewlyDecrypted = false
- } else {
- pk, err = crypto.UnmarshalEd25519PublicKey(headers.DevicePK)
- if err != nil {
- return nil, nil, errcode.ErrDeserialization.Wrap(err)
- }
-
- di.MK, err = m.getPrecomputedKey(ctx, groupPK, pk, headers.Counter)
- if err != nil {
- return nil, nil, errcode.ErrCryptoDecrypt.Wrap(err)
- }
- }
-
- return m.openPayload(di, pk, payload, headers)
-}
-
-// openPayload opens the payload of a message envelope with the given key and returns the decrypted message with the DecryptInfo struct.
-func (m *MessageKeystore) openPayload(di *DecryptInfo, pk crypto.PubKey, payload []byte, headers *protocoltypes.MessageHeaders) ([]byte, *DecryptInfo, error) {
- msg, ok := secretbox.Open(nil, payload, uint64AsNonce(headers.Counter), di.MK)
- if !ok {
- return nil, nil, errcode.ErrCryptoDecrypt.Wrap(fmt.Errorf("secret box failed to open message payload"))
- }
-
- if di.NewlyDecrypted {
- if ok, err := pk.Verify(msg, headers.Sig); !ok {
- return nil, nil, errcode.ErrCryptoSignatureVerification.Wrap(fmt.Errorf("unable to verify message signature"))
- } else if err != nil {
- return nil, nil, errcode.ErrCryptoSignatureVerification.Wrap(err)
- }
- }
-
- // Message was newly decrypted, we can save the message key and derive
- // future keys if necessary.
- return msg, di, nil
-}
-
-// GetKeyForCID retrieves the message key for the given message CID.
-func (m *MessageKeystore) GetKeyForCID(ctx context.Context, id cid.Cid) (*[32]byte, error) {
- if m == nil {
- return nil, errcode.ErrInvalidInput
- }
-
- if !id.Defined() {
- return nil, errcode.ErrInvalidInput
- }
-
- key, err := m.store.Get(ctx, idForMK(id))
- if err == datastore.ErrNotFound {
- return nil, errcode.ErrInvalidInput
- }
-
- keyArray, err := KeySliceToArray(key)
- if err != nil {
- return nil, errcode.ErrSerialization
- }
-
- return keyArray, nil
-}
-
-// GetPrecomputedKeyExpectedCount returns the number of precomputed keys that should be in the cache namespace of the keystore.
-func (m *MessageKeystore) GetPrecomputedKeyExpectedCount() int {
- if m == nil {
- return 0
- }
-
- return m.preComputedKeysCount
-}
-
-// putDeviceChainKey stores the given device secret for the given groupPK and devicePK.
-func (m *MessageKeystore) putDeviceChainKey(ctx context.Context, groupPK, device crypto.PubKey, ds *protocoltypes.DeviceSecret) error {
- if m == nil {
- return errcode.ErrInvalidInput
- }
-
- deviceRaw, err := device.Raw()
- if err != nil {
- return errcode.ErrSerialization.Wrap(err)
- }
-
- groupRaw, err := groupPK.Raw()
- if err != nil {
- return errcode.ErrSerialization.Wrap(err)
- }
-
- key := idForCurrentCK(groupRaw, deviceRaw)
-
- data, err := ds.Marshal()
- if err != nil {
- return errcode.ErrSerialization.Wrap(err)
- }
-
- err = m.store.Put(ctx, key, data)
- if err != nil {
- return errcode.ErrMessageKeyPersistencePut.Wrap(err)
- }
-
- return nil
-}
-
-// SealEnvelope encrypts the given payload and returns it as an envelope to be published on the group's store.
-// It retrieves the device's chain key from the keystore to encrypt the payload using symmetric encryption.
-// The payload is signed using the device's long term private key for the target group.
-// It also updates the device secret and stores the next message key in the cache.
-func (m *MessageKeystore) SealEnvelope(ctx context.Context, g *protocoltypes.Group, deviceSK crypto.PrivKey, payload []byte) ([]byte, error) {
- if m == nil {
- return nil, errcode.ErrInvalidInput
- }
-
- if deviceSK == nil || g == nil || m == nil {
- return nil, errcode.ErrInvalidInput
- }
-
- groupPK, err := g.GetPubKey()
- if err != nil {
- return nil, errcode.ErrDeserialization.Wrap(err)
- }
-
- m.lock.Lock()
- defer m.lock.Unlock()
-
- ds, err := m.GetDeviceChainKey(ctx, groupPK, deviceSK.GetPublic())
- if err != nil {
- return nil, errcode.ErrInternal.Wrap(fmt.Errorf("unable to get device chainkey: %w", err))
- }
-
- env, err := SealEnvelope(payload, ds, deviceSK, g)
- if err != nil {
- return nil, errcode.ErrCryptoEncrypt.Wrap(fmt.Errorf("unable to seal envelope: %w", err))
- }
-
- if err := m.DeriveDeviceSecret(ctx, g, deviceSK.GetPublic()); err != nil {
- return nil, errcode.ErrCryptoKeyGeneration.Wrap(err)
- }
-
- return env, nil
-}
-
-// DeriveDeviceSecret derives the next device secret from the current device secret and stores it in the cache.
-// It also updates the device secret in the keystore.
-func (m *MessageKeystore) DeriveDeviceSecret(ctx context.Context, g *protocoltypes.Group, devicePK crypto.PubKey) error {
- if m == nil || devicePK == nil {
- return errcode.ErrInvalidInput
- }
-
- groupPK, err := g.GetPubKey()
- if err != nil {
- return errcode.ErrDeserialization.Wrap(err)
- }
-
- ds, err := m.preComputeNextKey(ctx, groupPK, devicePK)
- if err != nil {
- return errcode.ErrCryptoKeyGeneration.Wrap(err)
- }
-
- if err = m.updateCurrentKey(ctx, groupPK, devicePK, ds); err != nil {
- return errcode.ErrCryptoKeyGeneration.Wrap(err)
- }
-
- return nil
-}
-
-// updateCurrentKey updates the current device secret in the keystore if the given device secret has a higher counter.
-func (m *MessageKeystore) updateCurrentKey(ctx context.Context, groupPK, pk crypto.PubKey, ds *protocoltypes.DeviceSecret) error {
- if m == nil {
- return errcode.ErrInvalidInput
- }
-
- currentCK, err := m.GetDeviceChainKey(ctx, groupPK, pk)
- if err != nil {
- return errcode.ErrInternal.Wrap(err)
- }
-
- if ds.Counter < currentCK.Counter {
- return nil
- }
-
- if err = m.putDeviceChainKey(ctx, groupPK, pk, ds); err != nil {
- return errcode.ErrInternal.Wrap(err)
- }
-
- return nil
-}
-
-// NewMessageKeystore instantiate a new MessageKeystore
-func NewMessageKeystore(s datastore.Datastore, logger *zap.Logger) *MessageKeystore {
- if logger == nil {
- logger = zap.NewNop()
- }
-
- return &MessageKeystore{
- preComputedKeysCount: 100,
- store: dssync.MutexWrap(s),
- logger: logger.Named("message-ks"),
- }
-}
-
-// nolint:deadcode,unused // NewInMemMessageKeystore instantiate a new MessageKeystore, useful for testing
-func NewInMemMessageKeystore(logger *zap.Logger) (*MessageKeystore, func()) {
- ds := dssync.MutexWrap(datastore.NewMapDatastore())
-
- return NewMessageKeystore(ds, logger), func() { _ = ds.Close() }
-}
-
-// OpenOutOfStoreMessage opens the given OutOfStoreMessage and returns the decrypted payload.
-// The signature is verified against the given devicePK.
-// It derives the next message key and stores it in the cache, but it doesn't update the device secret.
-func (m *MessageKeystore) OpenOutOfStoreMessage(ctx context.Context, envelope *protocoltypes.OutOfStoreMessage, groupPublicKey []byte) ([]byte, bool, error) {
- if m == nil || envelope == nil || len(groupPublicKey) == 0 {
- return nil, false, errcode.ErrInvalidInput
- }
-
- m.lock.Lock()
- defer m.lock.Unlock()
-
- gPK, err := crypto.UnmarshalEd25519PublicKey(groupPublicKey)
- if err != nil {
- return nil, false, errcode.ErrDeserialization.Wrap(err)
- }
-
- dPK, err := crypto.UnmarshalEd25519PublicKey(envelope.DevicePK)
- if err != nil {
- return nil, false, errcode.ErrDeserialization.Wrap(err)
- }
-
- _, c, err := cid.CidFromBytes(envelope.CID)
- if err != nil {
- return nil, false, errcode.ErrDeserialization.Wrap(err)
- }
-
- di := &DecryptInfo{NewlyDecrypted: true}
- if di.MK, err = m.GetKeyForCID(ctx, c); err == nil {
- di.NewlyDecrypted = false
- } else {
- di.MK, err = m.getPrecomputedKey(ctx, gPK, dPK, envelope.Counter)
- if err != nil {
- return nil, false, errcode.ErrCryptoDecrypt.Wrap(err)
- }
- }
-
- clear, di, err := m.openPayload(di, dPK, envelope.EncryptedPayload, &protocoltypes.MessageHeaders{
- Counter: envelope.Counter,
- DevicePK: envelope.DevicePK,
- Sig: envelope.Sig,
- })
- if err != nil {
- return nil, false, errcode.ErrCryptoDecrypt.Wrap(err)
- }
-
- if ok, err := dPK.Verify(clear, envelope.Sig); !ok {
- return nil, false, errcode.ErrCryptoSignatureVerification.Wrap(fmt.Errorf("unable to verify message signature"))
- } else if err != nil {
- return nil, false, errcode.ErrCryptoSignatureVerification.Wrap(err)
- }
-
- if _, err = m.preComputeNextKey(ctx, gPK, dPK); err != nil {
- return nil, false, errcode.ErrInternal.Wrap(err)
- }
-
- return clear, di.NewlyDecrypted, nil
-}
-
-// refKey returns the datastore key of the groupPK for the given push group reference.
-func (m *MessageKeystore) refKey(ref []byte) datastore.Key {
- return datastore.KeyWithNamespaces([]string{
- "outOfStoreGroupHint", base64.RawURLEncoding.EncodeToString(ref),
- })
-}
-
-// refFirstLastKey returns the datastore key of the FirstLastCounters struct for the given groupPK and devicePK.
-func (m *MessageKeystore) refFirstLastKey(groupPK, devicePK []byte) datastore.Key {
- return datastore.KeyWithNamespaces([]string{
- "outOfStoreGroupHint",
- base64.RawURLEncoding.EncodeToString(groupPK),
- base64.RawURLEncoding.EncodeToString(devicePK),
- })
-}
-
-// GetByPushGroupReference returns the groupPK associated with the given push group reference.
-func (m *MessageKeystore) GetByPushGroupReference(ctx context.Context, ref []byte) ([]byte, error) {
- return m.store.Get(ctx, m.refKey(ref))
-}
-
-// UpdatePushGroupReferences updates the push group references for the given devicePK and groupPK in the keystore.
-// It creates the references for the given range [first + precomputePushRefsCount] and [first - precomputePushRefsCount] and deletes the references out of range.
-func (m *MessageKeystore) UpdatePushGroupReferences(ctx context.Context, devicePK []byte, first uint64, group GroupWithSecret) error {
- refsExisting := []uint64(nil)
- refsToCreate := []uint64(nil)
-
- groupPushSecret, err := GetGroupPushSecret(group)
- if err != nil {
- return errcode.ErrCryptoKeyGeneration.Wrap(err)
- }
-
- currentFirst, currentLast, err := m.firstLastCachedGroupRefsForMember(ctx, devicePK, group)
- if err == nil {
- for i := currentFirst; i != currentLast; i++ {
- refsExisting = append(refsExisting, i)
- }
- }
-
- // keep previous refs
- last := first + precomputePushRefsCount
- first -= precomputePushRefsCount
- for i := first; i != last; i++ {
- found := false
-
- // Ignore refs that should be kept
- for j := 0; j < len(refsExisting); j++ {
- if refsExisting[j] == i {
- refsExisting[j] = refsExisting[len(refsExisting)-1]
- refsExisting = refsExisting[:len(refsExisting)-1]
- found = true
- break
- }
- }
-
- if !found {
- refsToCreate = append(refsToCreate, i)
- }
- }
-
- // Remove useless old refs
- for i := 0; i < len(refsExisting); i++ {
- ref, err := CreatePushGroupReference(devicePK, refsExisting[i], groupPushSecret)
- if err != nil {
- m.logger.Error("creating existing push group reference failed", logutil.PrivateBinary("ref", ref), zap.Error(err))
- continue
- }
-
- if err := m.store.Delete(ctx, m.refKey(ref)); err != nil {
- m.logger.Error("deleting existing push group reference failed", logutil.PrivateBinary("ref", ref), zap.Error(err))
- continue
- }
- }
-
- // Add new refs
- for i := 0; i < len(refsToCreate); i++ {
- ref, err := CreatePushGroupReference(devicePK, refsToCreate[i], groupPushSecret)
- if err != nil {
- m.logger.Error("creating new push group reference failed", logutil.PrivateBinary("ref", ref), zap.Error(err))
- continue
- }
-
- if err := m.store.Put(ctx, m.refKey(ref), group.GetPublicKey()); err != nil {
- m.logger.Error("putting new push group reference failed", logutil.PrivateBinary("ref", ref), zap.Error(err))
- continue
- }
- }
-
- // Update first/last
- if err := m.putFirstLastCachedGroupRefsForMember(ctx, first, last, devicePK, group); err != nil {
- m.logger.Error("putting first/last push group reference failed", zap.Error(err))
- }
-
- return nil
-}
-
-// firstLastCachedGroupRefsForMember returns the first and last cached group references counter for the given devicePK and groupPK.
-func (m *MessageKeystore) firstLastCachedGroupRefsForMember(ctx context.Context, devicePK []byte, group GroupWithSecret) (uint64, uint64, error) {
- key := m.refFirstLastKey(group.GetPublicKey(), devicePK)
- bytes, err := m.store.Get(ctx, key)
- if err != nil {
- return 0, 0, err
- }
-
- ret := protocoltypes.FirstLastCounters{}
- if err := ret.Unmarshal(bytes); err != nil {
- return 0, 0, err
- }
-
- return ret.First, ret.Last, nil
-}
-
-// putFirstLastCachedGroupRefsForMember puts the first and last cached group references counter for the given devicePK and groupPK.
-func (m *MessageKeystore) putFirstLastCachedGroupRefsForMember(ctx context.Context, first uint64, last uint64, devicePK []byte, group GroupWithSecret) error {
- key := m.refFirstLastKey(group.GetPublicKey(), devicePK)
-
- fistLast := protocoltypes.FirstLastCounters{
- First: first,
- Last: last,
- }
- bytes, err := fistLast.Marshal()
- if err != nil {
- return err
- }
-
- return m.store.Put(ctx, key, bytes)
-}
diff --git a/pkg/cryptoutil/keystore_message_utils.go b/pkg/cryptoutil/keystore_message_utils.go
deleted file mode 100644
index 1ed4a918..00000000
--- a/pkg/cryptoutil/keystore_message_utils.go
+++ /dev/null
@@ -1,159 +0,0 @@
-package cryptoutil
-
-import (
- "crypto/sha256"
- "encoding/binary"
- "encoding/hex"
- "fmt"
- "io"
- "io/ioutil"
-
- "github.com/gogo/protobuf/proto"
- "github.com/ipfs/go-cid"
- "github.com/ipfs/go-datastore"
- "github.com/libp2p/go-libp2p/core/crypto"
- "golang.org/x/crypto/hkdf"
- "golang.org/x/crypto/nacl/secretbox"
-
- "berty.tech/weshnet/pkg/errcode"
- "berty.tech/weshnet/pkg/protocoltypes"
-)
-
-func SealPayload(payload []byte, ds *protocoltypes.DeviceSecret, deviceSK crypto.PrivKey, g *protocoltypes.Group) ([]byte, []byte, error) {
- var (
- msgKey [32]byte
- err error
- )
-
- sig, err := deviceSK.Sign(payload)
- if err != nil {
- return nil, nil, errcode.ErrCryptoSignature.Wrap(err)
- }
-
- if _, msgKey, err = deriveNextKeys(ds.ChainKey, nil, g.GetPublicKey()); err != nil {
- return nil, nil, errcode.ErrCryptoKeyGeneration.Wrap(err)
- }
-
- return secretbox.Seal(nil, payload, uint64AsNonce(ds.Counter+1), &msgKey), sig, nil
-}
-
-func SealEnvelope(payload []byte, ds *protocoltypes.DeviceSecret, deviceSK crypto.PrivKey, g *protocoltypes.Group) ([]byte, error) {
- encryptedPayload, sig, err := SealPayload(payload, ds, deviceSK, g)
- if err != nil {
- return nil, errcode.ErrCryptoEncrypt.Wrap(err)
- }
-
- devicePKRaw, err := deviceSK.GetPublic().Raw()
- if err != nil {
- return nil, errcode.ErrSerialization.Wrap(err)
- }
-
- h := &protocoltypes.MessageHeaders{
- Counter: ds.Counter + 1,
- DevicePK: devicePKRaw,
- Sig: sig,
- }
-
- headers, err := proto.Marshal(h)
- if err != nil {
- return nil, errcode.ErrSerialization.Wrap(err)
- }
-
- nonce, err := GenerateNonce()
- if err != nil {
- return nil, errcode.ErrCryptoNonceGeneration.Wrap(err)
- }
-
- encryptedHeaders := secretbox.Seal(nil, headers, nonce, GetSharedSecret(g))
-
- env, err := proto.Marshal(&protocoltypes.MessageEnvelope{
- MessageHeaders: encryptedHeaders,
- Message: encryptedPayload,
- Nonce: nonce[:],
- })
- if err != nil {
- return nil, errcode.ErrSerialization.Wrap(err)
- }
-
- return env, nil
-}
-
-func OpenEnvelopeHeaders(data []byte, g *protocoltypes.Group) (*protocoltypes.MessageEnvelope, *protocoltypes.MessageHeaders, error) {
- env := &protocoltypes.MessageEnvelope{}
- err := env.Unmarshal(data)
- if err != nil {
- return nil, nil, errcode.ErrDeserialization.Wrap(err)
- }
-
- nonce, err := NonceSliceToArray(env.Nonce)
- if err != nil {
- return nil, nil, errcode.ErrSerialization.Wrap(err)
- }
-
- headersBytes, ok := secretbox.Open(nil, env.MessageHeaders, nonce, GetSharedSecret(g))
- if !ok {
- return nil, nil, errcode.ErrCryptoDecrypt.Wrap(fmt.Errorf("secretbox failed to open headers"))
- }
-
- headers := &protocoltypes.MessageHeaders{}
- if err := headers.Unmarshal(headersBytes); err != nil {
- return nil, nil, errcode.ErrDeserialization.Wrap(err)
- }
-
- return env, headers, nil
-}
-
-func deriveNextKeys(ck []byte, salt []byte, groupID []byte) ([]byte, [32]byte, error) {
- var (
- nextMsg [32]byte
- err error
- )
-
- // Salt length must be equal to hash length (64 bytes for sha256)
- hash := sha256.New
-
- // Generate Pseudo Random Key using ck as IKM and salt
- prk := hkdf.Extract(hash, ck, salt)
- if len(prk) == 0 {
- return nil, nextMsg, errcode.ErrInternal
- }
-
- // Expand using extracted prk and groupID as info (kind of namespace)
- kdf := hkdf.Expand(hash, prk, groupID)
-
- // Generate next KDF and message keys
- nextCK, err := ioutil.ReadAll(io.LimitReader(kdf, 32))
- if err != nil {
- return nil, nextMsg, errcode.ErrCryptoKeyGeneration.Wrap(err)
- }
-
- nextMsgSlice, err := ioutil.ReadAll(io.LimitReader(kdf, 32))
- if err != nil {
- return nil, nextMsg, errcode.ErrCryptoKeyGeneration.Wrap(err)
- }
-
- copy(nextMsg[:], nextMsgSlice)
-
- return nextCK, nextMsg, nil
-}
-
-func idForPrecomputeMK(groupPK, pk []byte, counter uint64) datastore.Key {
- return datastore.KeyWithNamespaces([]string{"precomputedMessageKeys", hex.EncodeToString(groupPK), hex.EncodeToString(pk), fmt.Sprintf("%d", counter)})
-}
-
-func idForCurrentCK(groupPK, pk []byte) datastore.Key {
- return datastore.KeyWithNamespaces([]string{"chainKeyForDeviceOnGroup", hex.EncodeToString(groupPK), hex.EncodeToString(pk)})
-}
-
-func idForMK(id cid.Cid) datastore.Key {
- // TODO: specify the id
- return datastore.KeyWithNamespaces([]string{"messageKeyForCIDs", id.String()})
-}
-
-func uint64AsNonce(val uint64) *[24]byte {
- var nonce [24]byte
-
- binary.BigEndian.PutUint64(nonce[:], val)
-
- return &nonce
-}
diff --git a/pkg/cryptoutil/keystore_message_utils_test.go b/pkg/cryptoutil/keystore_message_utils_test.go
deleted file mode 100644
index 55bb45ec..00000000
--- a/pkg/cryptoutil/keystore_message_utils_test.go
+++ /dev/null
@@ -1,616 +0,0 @@
-package cryptoutil_test
-
-import (
- "context"
- "encoding/hex"
- "fmt"
- "os"
- "path"
- "testing"
-
- cid "github.com/ipfs/go-cid"
- keystore "github.com/ipfs/go-ipfs-keystore"
- "github.com/libp2p/go-libp2p/core/crypto"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- "go.uber.org/zap"
-
- "berty.tech/weshnet"
- "berty.tech/weshnet/pkg/cryptoutil"
- "berty.tech/weshnet/pkg/protocoltypes"
- "berty.tech/weshnet/pkg/testutil"
-)
-
-const precomputePushRefsCount = uint64(100)
-
-func addDummyMemberInMetadataStore(ctx context.Context, t testing.TB, ms *weshnet.MetadataStore, g *protocoltypes.Group, memberPK crypto.PubKey, join bool) (crypto.PubKey, *protocoltypes.DeviceSecret) {
- t.Helper()
-
- acc := cryptoutil.NewDeviceKeystore(keystore.NewMemKeystore(), nil)
- md, err := acc.MemberDeviceForGroup(g)
- assert.NoError(t, err)
-
- ds, err := cryptoutil.NewDeviceSecret()
- assert.NoError(t, err)
-
- if join {
- _, err = weshnet.MetadataStoreAddDeviceToGroup(ctx, ms, g, md)
- assert.NoError(t, err)
- }
-
- _, err = weshnet.MetadataStoreSendSecret(ctx, ms, g, md, memberPK, ds)
- assert.NoError(t, err)
-
- return md.PrivateDevice().GetPublic(), ds
-}
-
-func mustDeviceSecret(t testing.TB) func(ds *protocoltypes.DeviceSecret, err error) *protocoltypes.DeviceSecret {
- return func(ds *protocoltypes.DeviceSecret, err error) *protocoltypes.DeviceSecret {
- t.Helper()
-
- if err != nil {
- t.Fatal(err)
- }
-
- return ds
- }
-}
-
-func mustMessageHeaders(t testing.TB, sk crypto.PrivKey, counter uint64, payload []byte) *protocoltypes.MessageHeaders {
- t.Helper()
-
- pkB, err := sk.GetPublic().Raw()
- if err != nil {
- t.Fatal(err)
- }
-
- sig, err := sk.Sign(payload)
- if err != nil {
- t.Fatal(err)
- }
-
- return &protocoltypes.MessageHeaders{
- Counter: counter,
- DevicePK: pkB,
- Sig: sig,
- }
-}
-
-func Test_EncryptMessagePayload(t *testing.T) {
- logger := zap.NewNop()
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- g, gSK, err := weshnet.NewGroupMultiMember()
- assert.NoError(t, err)
-
- _ = gSK
-
- acc1 := cryptoutil.NewDeviceKeystore(keystore.NewMemKeystore(), nil)
-
- omd1, err := acc1.MemberDeviceForGroup(g)
- assert.NoError(t, err)
-
- ds1, err := cryptoutil.NewDeviceSecret()
- assert.NoError(t, err)
-
- ds2, err := cryptoutil.NewDeviceSecret()
- assert.NoError(t, err)
-
- initialCounter := ds1.Counter
- firstSK := append([]byte(nil), ds1.ChainKey...)
-
- acc2 := cryptoutil.NewDeviceKeystore(keystore.NewMemKeystore(), nil)
-
- omd2, err := acc2.MemberDeviceForGroup(g)
-
- mkh1, cleanup := cryptoutil.NewInMemMessageKeystore(logger)
- defer cleanup()
-
- mkh2, cleanup := cryptoutil.NewInMemMessageKeystore(logger)
- defer cleanup()
-
- gc1 := weshnet.NewContextGroup(g, nil, nil, mkh1, omd1, nil)
- gc2 := weshnet.NewContextGroup(g, nil, nil, mkh2, omd2, nil)
-
- err = mkh1.RegisterChainKey(ctx, g, gc1.DevicePubKey(), ds1, true)
- assert.NoError(t, err)
-
- err = mkh2.RegisterChainKey(ctx, g, gc2.DevicePubKey(), ds2, true)
- assert.NoError(t, err)
-
- payloadRef1 := []byte("ok, this is the first test")
- payloadRef2 := []byte("so, this is a second test")
- payloadRef3 := []byte("this will be posted many times")
-
- err = mkh2.RegisterChainKey(ctx, g, omd1.PrivateDevice().GetPublic(), ds1, false)
- assert.NoError(t, err)
-
- gPK, err := g.GetPubKey()
- assert.NoError(t, err)
-
- assert.Equal(t, mustDeviceSecret(t)(mkh1.GetDeviceChainKey(ctx, gPK, omd1.PrivateDevice().GetPublic())).ChainKey, firstSK)
-
- payloadEnc1, _, err := cryptoutil.SealPayload(payloadRef1, mustDeviceSecret(t)(mkh1.GetDeviceChainKey(ctx, gPK, omd1.PrivateDevice().GetPublic())), omd1.PrivateDevice(), g)
- assert.NoError(t, err)
-
- // secret is derived by SealEnvelope
- err = mkh1.DeriveDeviceSecret(ctx, g, omd1.PrivateDevice().GetPublic())
- assert.NoError(t, err)
-
- assert.NotEqual(t, hex.EncodeToString(payloadRef1), hex.EncodeToString(payloadEnc1))
-
- // Messages are encrypted with DeviceSecret.Counter
- // uint64 overflows to 0, which is the expected behaviour
-
- // Test with a wrong counter value
- payloadClr1, decryptInfo, err := mkh2.OpenPayload(ctx, cid.Undef, gPK, payloadEnc1, mustMessageHeaders(t, omd1.PrivateDevice(), initialCounter+2, payloadRef1))
- assert.Error(t, err)
- assert.Nil(t, decryptInfo)
- assert.Equal(t, "", string(payloadClr1))
-
- // Test with a valid counter value, but no CID (so no cache)
- payloadClr1, decryptInfo, err = mkh2.OpenPayload(ctx, cid.Undef, gPK, payloadEnc1, mustMessageHeaders(t, omd1.PrivateDevice(), initialCounter+1, payloadRef1))
- assert.NoError(t, err)
- assert.Equal(t, string(payloadRef1), string(payloadClr1))
-
- err = mkh2.PostDecryptActions(ctx, decryptInfo, g, omd2.PrivateDevice().GetPublic(), mustMessageHeaders(t, omd1.PrivateDevice(), initialCounter+1, payloadRef1))
- assert.NoError(t, err)
-
- ds, err := mkh1.GetDeviceChainKey(ctx, gPK, omd1.PrivateDevice().GetPublic())
- assert.NoError(t, err)
-
- assert.Equal(t, ds.Counter, initialCounter+1)
- assert.NotEqual(t, ds.ChainKey, firstSK)
-
- payloadEnc2, _, err := cryptoutil.SealPayload(payloadRef1, ds, omd1.PrivateDevice(), g)
- assert.NoError(t, err)
-
- err = mkh1.DeriveDeviceSecret(ctx, g, omd1.PrivateDevice().GetPublic())
- assert.NoError(t, err)
-
- // Ensure that encrypted message is not the same as the first message
- assert.NotEqual(t, hex.EncodeToString(payloadRef1), hex.EncodeToString(payloadEnc2))
- assert.NotEqual(t, hex.EncodeToString(payloadEnc1), hex.EncodeToString(payloadEnc2))
-
- payloadClr2, decryptInfo, err := mkh2.OpenPayload(ctx, cid.Undef, gPK, payloadEnc2, mustMessageHeaders(t, omd1.PrivateDevice(), initialCounter+2, payloadRef1))
- assert.NoError(t, err)
-
- err = mkh2.PostDecryptActions(ctx, decryptInfo, g, omd2.PrivateDevice().GetPublic(), mustMessageHeaders(t, omd1.PrivateDevice(), initialCounter+2, payloadRef1))
- assert.NoError(t, err)
-
- assert.Equal(t, string(payloadRef1), string(payloadClr2))
-
- // Make sure that a message without a CID can't be decrypted twice
- payloadClr2, decryptInfo, err = mkh2.OpenPayload(ctx, cid.Undef, gPK, payloadEnc2, mustMessageHeaders(t, omd1.PrivateDevice(), initialCounter+1, payloadRef1))
- assert.Error(t, err)
- assert.Equal(t, "", string(payloadClr2))
-
- ds, err = mkh1.GetDeviceChainKey(ctx, gPK, omd1.PrivateDevice().GetPublic())
- assert.NoError(t, err)
-
- // Make sure that a message a CID can be decrypted twice
- payloadEnc3, _, err := cryptoutil.SealPayload(payloadRef2, ds, omd1.PrivateDevice(), g)
- assert.NoError(t, err)
-
- err = mkh1.DeriveDeviceSecret(ctx, g, omd1.PrivateDevice().GetPublic())
- assert.NoError(t, err)
-
- dummyCID1, err := cid.Parse("QmbdQXQh9B2bWZgZJqfbjNPV5jGN2owbQ3vjeYsaDaCDqU")
- assert.NoError(t, err)
-
- dummyCID2, err := cid.Parse("Qmf8oj9wbfu73prNAA1cRQVDqA52gD5B3ApnYQQjcjffH4")
- assert.NoError(t, err)
-
- // Not decrypted message yet, wrong counter value
- payloadClr3, decryptInfo, err := mkh2.OpenPayload(ctx, dummyCID1, gPK, payloadEnc3, mustMessageHeaders(t, omd1.PrivateDevice(), initialCounter+2, payloadRef2))
- assert.Error(t, err)
- assert.Equal(t, "", string(payloadClr3))
-
- payloadClr3, decryptInfo, err = mkh2.OpenPayload(ctx, dummyCID1, gPK, payloadEnc3, mustMessageHeaders(t, omd1.PrivateDevice(), initialCounter+3, payloadRef2))
- assert.NoError(t, err)
- assert.Equal(t, string(payloadRef2), string(payloadClr3))
-
- err = mkh2.PostDecryptActions(ctx, decryptInfo, g, omd2.PrivateDevice().GetPublic(), mustMessageHeaders(t, omd1.PrivateDevice(), initialCounter+3, payloadRef2))
- assert.NoError(t, err)
-
- payloadClr3, decryptInfo, err = mkh2.OpenPayload(ctx, dummyCID1, gPK, payloadEnc3, mustMessageHeaders(t, omd1.PrivateDevice(), initialCounter+3, payloadRef2))
- assert.NoError(t, err)
- assert.Equal(t, string(payloadRef2), string(payloadClr3))
-
- err = mkh2.PostDecryptActions(ctx, decryptInfo, g, omd2.PrivateDevice().GetPublic(), mustMessageHeaders(t, omd1.PrivateDevice(), initialCounter+3, payloadRef2))
- assert.NoError(t, err)
-
- // Wrong CID
- payloadClr3, decryptInfo, err = mkh2.OpenPayload(ctx, dummyCID2, gPK, payloadEnc3, mustMessageHeaders(t, omd1.PrivateDevice(), initialCounter+3, payloadRef2))
- assert.Error(t, err)
- assert.Equal(t, "", string(payloadClr3))
-
- // Reused CID, wrong counter value
- payloadClr3, decryptInfo, err = mkh2.OpenPayload(ctx, dummyCID1, gPK, payloadEnc3, mustMessageHeaders(t, omd1.PrivateDevice(), initialCounter+4, payloadRef2))
- assert.Error(t, err)
- assert.Equal(t, "", string(payloadClr3))
-
- massExpected := uint64(200)
-
- // Test appending 200 messages, to ensure new secrets are generated correctly
- for i := uint64(0); i < massExpected; i++ {
- ds, err = mkh1.GetDeviceChainKey(ctx, gPK, omd1.PrivateDevice().GetPublic())
- assert.NoError(t, err)
-
- payloadEnc, _, err := cryptoutil.SealPayload(payloadRef3, ds, omd1.PrivateDevice(), g)
- assert.NoError(t, err)
-
- err = mkh1.DeriveDeviceSecret(ctx, g, omd1.PrivateDevice().GetPublic())
- assert.NoError(t, err)
-
- ds, err = mkh1.GetDeviceChainKey(ctx, gPK, omd1.PrivateDevice().GetPublic())
- assert.NoError(t, err)
-
- counter := ds.Counter
-
- payloadClr, decryptInfo, err := mkh2.OpenPayload(ctx, cid.Undef, gPK, payloadEnc, mustMessageHeaders(t, omd1.PrivateDevice(), counter, payloadRef3))
- if !assert.NoError(t, err) {
- t.Fatalf("failed at i = %d", i)
- }
-
- err = mkh2.PostDecryptActions(ctx, decryptInfo, g, omd2.PrivateDevice().GetPublic(), mustMessageHeaders(t, omd1.PrivateDevice(), counter, payloadRef3))
- assert.NoError(t, err)
-
- assert.Equal(t, string(payloadRef3), string(payloadClr))
- }
-
- ds, err = mkh1.GetDeviceChainKey(ctx, gPK, omd1.PrivateDevice().GetPublic())
- assert.NoError(t, err)
-
- assert.Equal(t, initialCounter+massExpected+3, ds.Counter)
-}
-
-func Test_EncryptMessageEnvelope(t *testing.T) {
- logger := zap.NewNop()
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- g, _, err := weshnet.NewGroupMultiMember()
- assert.NoError(t, err)
-
- acc1 := cryptoutil.NewDeviceKeystore(keystore.NewMemKeystore(), nil)
- mkh1, cleanup := cryptoutil.NewInMemMessageKeystore(logger)
- defer cleanup()
-
- omd1, err := acc1.MemberDeviceForGroup(g)
- assert.NoError(t, err)
-
- gc1 := weshnet.NewContextGroup(g, nil, nil, mkh1, omd1, nil)
-
- ds1, err := weshnet.NewDeviceSecret()
- assert.NoError(t, err)
-
- err = mkh1.RegisterChainKey(ctx, g, gc1.DevicePubKey(), ds1, true)
- assert.NoError(t, err)
-
- acc2 := cryptoutil.NewDeviceKeystore(keystore.NewMemKeystore(), nil)
- mkh2, cleanup := cryptoutil.NewInMemMessageKeystore(logger)
- defer cleanup()
-
- omd2, err := acc2.MemberDeviceForGroup(g)
- assert.NoError(t, err)
-
- ds2, err := cryptoutil.NewDeviceSecret()
- assert.NoError(t, err)
-
- payloadRef1, err := (&protocoltypes.EncryptedMessage{Plaintext: []byte("Test payload 1")}).Marshal()
- assert.NoError(t, err)
-
- err = mkh2.RegisterChainKey(ctx, g, omd2.PrivateDevice().GetPublic(), ds2, true)
- assert.NoError(t, err)
-
- err = mkh2.RegisterChainKey(ctx, g, omd1.PrivateDevice().GetPublic(), ds1, false)
- assert.NoError(t, err)
-
- env1, err := cryptoutil.SealEnvelope(payloadRef1, ds1, omd1.PrivateDevice(), g)
- assert.NoError(t, err)
-
- headers, payloadClr1, err := openEnvelope(ctx, t, mkh2, g, omd2.PrivateDevice().GetPublic(), env1, cid.Undef)
- assert.NoError(t, err)
-
- devRaw, err := omd1.PrivateDevice().GetPublic().Raw()
- assert.Equal(t, headers.DevicePK, devRaw)
-
- payloadClrlBytes, err := payloadClr1.Marshal()
- assert.NoError(t, err)
- assert.Equal(t, payloadRef1, payloadClrlBytes)
-}
-
-func Test_EncryptMessageEnvelopeAndDerive(t *testing.T) {
- logger := zap.NewNop()
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- g, _, err := weshnet.NewGroupMultiMember()
- assert.NoError(t, err)
-
- acc1 := cryptoutil.NewDeviceKeystore(keystore.NewMemKeystore(), nil)
- acc2 := cryptoutil.NewDeviceKeystore(keystore.NewMemKeystore(), nil)
-
- omd1, err := acc1.MemberDeviceForGroup(g)
- assert.NoError(t, err)
-
- omd2, err := acc2.MemberDeviceForGroup(g)
- assert.NoError(t, err)
-
- ds1, err := cryptoutil.NewDeviceSecret()
- assert.NoError(t, err)
-
- mkh1, cleanup := cryptoutil.NewInMemMessageKeystore(logger)
- defer cleanup()
-
- mkh2, cleanup := cryptoutil.NewInMemMessageKeystore(logger)
- defer cleanup()
-
- err = mkh1.RegisterChainKey(ctx, g, omd1.PrivateDevice().GetPublic(), ds1, true)
- assert.NoError(t, err)
-
- gPK, err := g.GetPubKey()
- assert.NoError(t, err)
-
- gc1 := weshnet.NewContextGroup(g, nil, nil, mkh1, omd1, nil)
-
- ds2, err := cryptoutil.NewDeviceSecret()
- assert.NoError(t, err)
-
- err = mkh2.RegisterChainKey(ctx, g, omd2.PrivateDevice().GetPublic(), ds2, true)
- assert.NoError(t, err)
-
- err = mkh2.RegisterChainKey(ctx, g, omd1.PrivateDevice().GetPublic(), ds1, false)
- assert.NoError(t, err)
-
- initialCounter := ds1.Counter
-
- for i := 0; i < 1000; i++ {
- payloadRef, err := (&protocoltypes.EncryptedMessage{Plaintext: []byte("Test payload 1")}).Marshal()
- assert.NoError(t, err)
- envEncrypted, err := mkh1.SealEnvelope(ctx, g, omd1.PrivateDevice(), payloadRef)
- assert.NoError(t, err)
-
- ds, err := mkh1.GetDeviceChainKey(ctx, gPK, gc1.DevicePubKey())
- if !assert.NoError(t, err) {
- t.Fatalf("failed at i = %d", i)
- }
- assert.Equal(t, ds.Counter, initialCounter+uint64(i+1))
-
- headers, payloadClr, err := openEnvelope(ctx, t, mkh2, g, omd2.PrivateDevice().GetPublic(), envEncrypted, cid.Undef)
- if !assert.NoError(t, err) {
- t.Fatalf("failed at i = %d", i)
- }
-
- if assert.NotNil(t, headers) && assert.NotNil(t, payloadClr) {
- devRaw, err := omd1.PrivateDevice().GetPublic().Raw()
- assert.NoError(t, err)
-
- assert.Equal(t, headers.DevicePK, devRaw)
-
- payloadClrBytes, err := payloadClr.Marshal()
- assert.NoError(t, err)
- assert.Equal(t, payloadRef, payloadClrBytes)
- } else {
- break
- }
- }
-}
-
-func testMessageKeyHolderCatchUp(t *testing.T, expectedNewDevices int, isSlow bool) {
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- if isSlow {
- testutil.FilterSpeed(t, testutil.Slow)
- }
-
- dir := path.Join(os.TempDir(), fmt.Sprintf("%d", os.Getpid()), "MessageKeyHolderCatchUp")
- defer os.RemoveAll(dir)
-
- peers, _, cleanup := weshnet.CreatePeersWithGroupTest(ctx, t, dir, 1, 1)
- defer cleanup()
-
- peer := peers[0]
-
- mkh1 := peer.MKS
- ms1 := peer.GC.MetadataStore()
-
- devicesPK := make([]crypto.PubKey, expectedNewDevices)
- deviceSecrets := make([]*protocoltypes.DeviceSecret, expectedNewDevices)
-
- for i := 0; i < expectedNewDevices; i++ {
- devicesPK[i], deviceSecrets[i] = addDummyMemberInMetadataStore(ctx, t, ms1, peer.GC.Group(), peer.GC.MemberPubKey(), true)
- }
-
- for range peer.GC.FillMessageKeysHolderUsingPreviousData() {
- }
-
- gPK, err := peer.GC.Group().GetPubKey()
- require.NoError(t, err)
-
- for i, dPK := range devicesPK {
- ds, err := mkh1.GetDeviceChainKey(ctx, gPK, dPK)
- if assert.NoError(t, err) {
- assert.Equal(t, deviceSecrets[i].Counter+uint64(mkh1.GetPrecomputedKeyExpectedCount()), ds.Counter)
- // Not testing chain key value as we need to derive it from the generated value
- } else {
- t.Fatalf("failed at iteration %d", i)
- }
- }
-}
-
-func TestMessageKeyHolderCatchUp(t *testing.T) {
- for _, testCase := range []struct {
- expectedNewDevices int
- slow bool
- }{
- {
- expectedNewDevices: 2,
- slow: false,
- },
- {
- expectedNewDevices: 10,
- slow: true,
- },
- } {
- testMessageKeyHolderCatchUp(t, testCase.expectedNewDevices, testCase.slow)
- }
-}
-
-func testMessageKeyHolderSubscription(t *testing.T, expectedNewDevices int, isSlow bool) {
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- if isSlow {
- testutil.FilterSpeed(t, testutil.Slow)
- }
-
- dir := path.Join(os.TempDir(), fmt.Sprintf("%d", os.Getpid()), "MessageKeyHolderSubscription")
- defer os.RemoveAll(dir)
-
- peers, gSK, cleanup := weshnet.CreatePeersWithGroupTest(ctx, t, dir, 1, 1)
- defer cleanup()
-
- peer := peers[0]
-
- mkh1 := peer.MKS
- ms1 := peer.GC.MetadataStore()
-
- devicesPK := make([]crypto.PubKey, expectedNewDevices)
- deviceSecrets := make([]*protocoltypes.DeviceSecret, expectedNewDevices)
-
- ch := peer.GC.FillMessageKeysHolderUsingNewData()
-
- for i := 0; i < expectedNewDevices; i++ {
- devicesPK[i], deviceSecrets[i] = addDummyMemberInMetadataStore(ctx, t, ms1, peer.GC.Group(), peer.GC.MemberPubKey(), true)
- }
-
- i := 0
- for range ch {
- i++
- if i == expectedNewDevices {
- break
- }
- }
-
- for i, dPK := range devicesPK {
- ds, err := mkh1.GetDeviceChainKey(ctx, gSK.GetPublic(), dPK)
- if assert.NoError(t, err) {
- assert.Equal(t, deviceSecrets[i].Counter+uint64(mkh1.GetPrecomputedKeyExpectedCount()), ds.Counter)
- // Not testing chain key value as we need to derive it from the generated value
- }
- }
-}
-
-func TestMessageKeyHolderSubscription(t *testing.T) {
- for _, testCase := range []struct {
- expectedNewDevices int
- slow bool
- }{
- {
- expectedNewDevices: 2,
- slow: false,
- },
- {
- expectedNewDevices: 10,
- slow: true,
- },
- } {
- testMessageKeyHolderSubscription(t, testCase.expectedNewDevices, testCase.slow)
- }
-}
-
-func Test_PushGroupReferences(t *testing.T) {
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- logger := zap.NewNop()
-
- g, _, err := weshnet.NewGroupMultiMember()
- assert.NoError(t, err)
-
- acc := cryptoutil.NewDeviceKeystore(keystore.NewMemKeystore(), nil)
-
- omd, err := acc.MemberDeviceForGroup(g)
- assert.NoError(t, err)
-
- devicePK, err := omd.Public().Device.Raw()
- assert.NoError(t, err)
-
- ds, err := cryptoutil.NewDeviceSecret()
- assert.NoError(t, err)
-
- mkh, cleanup := cryptoutil.NewInMemMessageKeystore(logger)
- defer cleanup()
-
- // test with the ds counter
- updateAndTestPushGroupReferences(ctx, mkh, devicePK, ds.Counter, g, t)
-
- // do the same test with a new device secret counter
- // so we can test if old references are deleted
- updateAndTestPushGroupReferences(ctx, mkh, devicePK, ds.Counter+10, g, t)
-}
-
-func updateAndTestPushGroupReferences(ctx context.Context, mkh *cryptoutil.MessageKeystore, devicePK []byte, counter uint64, g *protocoltypes.Group, t *testing.T) {
- // get the group push secret, used to create the push group references
- groupPushSecret, err := cryptoutil.GetGroupPushSecret(g)
- assert.NoError(t, err)
-
- // update the push group references
- err = mkh.UpdatePushGroupReferences(ctx, devicePK, counter, g)
- assert.NoError(t, err)
-
- // test that the push group references are updated
- // refs start counter - 100 to counter + 100
- start := counter - precomputePushRefsCount
- end := counter + precomputePushRefsCount
-
- for i := start; i < end; i++ {
- // compute the push group reference
- pushGroupRef, err := cryptoutil.CreatePushGroupReference(devicePK, i, groupPushSecret)
- assert.NoError(t, err)
-
- _, err = mkh.GetByPushGroupReference(ctx, pushGroupRef)
- assert.NoError(t, err)
- }
-
- // test boundary conditions
-
- // before the start counter
- {
- before := counter - precomputePushRefsCount - 1
- pushGroupRef, err := cryptoutil.CreatePushGroupReference(devicePK, before, groupPushSecret)
- assert.NoError(t, err)
- _, err = mkh.GetByPushGroupReference(ctx, pushGroupRef)
- assert.Error(t, err)
- }
-
- // after the end counter
- {
- end := counter + precomputePushRefsCount + 1
- pushGroupRef, err := cryptoutil.CreatePushGroupReference(devicePK, end, groupPushSecret)
- assert.NoError(t, err)
- _, err = mkh.GetByPushGroupReference(ctx, pushGroupRef)
- assert.Error(t, err)
- }
-}
-
-// openEnvelope opens a MessageEnvelope and returns the decrypted message.
-// It performs all the necessary steps to decrypt the message.
-func openEnvelope(ctx context.Context, t testing.TB, mk *cryptoutil.MessageKeystore, g *protocoltypes.Group, ownPK crypto.PubKey, data []byte, id cid.Cid) (*protocoltypes.MessageHeaders, *protocoltypes.EncryptedMessage, error) {
- t.Helper()
-
- assert.NotNil(t, mk)
- assert.NotNil(t, g)
-
- env, headers, err := cryptoutil.OpenEnvelopeHeaders(data, g)
- assert.NoError(t, err)
-
- msg, err := mk.OpenEnvelopePayload(ctx, env, headers, g, ownPK, id)
- assert.NoError(t, err)
-
- return headers, msg, nil
-}
diff --git a/pkg/cryptoutil/signer_wrapper.go b/pkg/cryptoutil/signer_wrapper.go
new file mode 100644
index 00000000..1f88f998
--- /dev/null
+++ b/pkg/cryptoutil/signer_wrapper.go
@@ -0,0 +1,28 @@
+package cryptoutil
+
+import (
+ stdcrypto "crypto"
+ "io"
+
+ libp2p_ci "github.com/libp2p/go-libp2p/core/crypto"
+)
+
+func NewFuncSigner(key libp2p_ci.PubKey, signer func([]byte) ([]byte, error)) stdcrypto.Signer {
+ return &funcSigner{
+ pubKey: key,
+ signer: signer,
+ }
+}
+
+type funcSigner struct {
+ pubKey libp2p_ci.PubKey
+ signer func([]byte) ([]byte, error)
+}
+
+func (f *funcSigner) Public() stdcrypto.PublicKey {
+ return f.pubKey
+}
+
+func (f *funcSigner) Sign(_ io.Reader, digest []byte, _ stdcrypto.SignerOpts) (signature []byte, err error) {
+ return f.signer(digest)
+}
diff --git a/pkg/protocoltypes/group.go b/pkg/protocoltypes/group.go
index 4d4b2b71..2f8631d4 100644
--- a/pkg/protocoltypes/group.go
+++ b/pkg/protocoltypes/group.go
@@ -1,11 +1,16 @@
package protocoltypes
import (
+ crand "crypto/rand"
"encoding/hex"
+ "io"
"github.com/libp2p/go-libp2p/core/crypto"
"golang.org/x/crypto/ed25519"
+ "golang.org/x/crypto/hkdf"
+ "golang.org/x/crypto/sha3"
+ "berty.tech/weshnet/pkg/cryptoutil"
"berty.tech/weshnet/pkg/errcode"
)
@@ -73,3 +78,87 @@ func (m *Group) Copy() *Group {
SignPub: m.SignPub,
}
}
+
+const CurrentGroupVersion = 1
+
+// NewGroupMultiMember creates a new Group object and an invitation to be used by
+// the first member of the group
+func NewGroupMultiMember() (*Group, crypto.PrivKey, error) {
+ priv, pub, err := crypto.GenerateEd25519Key(crand.Reader)
+ if err != nil {
+ return nil, nil, errcode.ErrCryptoKeyGeneration.Wrap(err)
+ }
+
+ pubBytes, err := pub.Raw()
+ if err != nil {
+ return nil, nil, errcode.ErrSerialization.Wrap(err)
+ }
+
+ signing, _, err := crypto.GenerateEd25519Key(crand.Reader)
+ if err != nil {
+ return nil, nil, errcode.ErrCryptoKeyGeneration.Wrap(err)
+ }
+
+ signingBytes, err := cryptoutil.SeedFromEd25519PrivateKey(signing)
+ if err != nil {
+ return nil, nil, errcode.ErrSerialization.Wrap(err)
+ }
+
+ skSig, err := priv.Sign(signingBytes)
+ if err != nil {
+ return nil, nil, errcode.ErrCryptoSignature.Wrap(err)
+ }
+
+ group := &Group{
+ PublicKey: pubBytes,
+ Secret: signingBytes,
+ SecretSig: skSig,
+ GroupType: GroupTypeMultiMember,
+ }
+
+ updateKey, err := group.GetLinkKeyArray()
+ if err != nil {
+ return nil, nil, errcode.ErrCryptoKeyGeneration.Wrap(err)
+ }
+
+ linkKeySig, err := priv.Sign(updateKey[:])
+ if err != nil {
+ return nil, nil, errcode.ErrCryptoSignature.Wrap(err)
+ }
+
+ group.LinkKeySig = linkKeySig
+
+ return group, priv, nil
+}
+
+func ComputeLinkKey(publicKey, secret []byte) (*[cryptoutil.KeySize]byte, error) {
+ arr := [cryptoutil.KeySize]byte{}
+
+ kdf := hkdf.New(sha3.New256, secret, nil, publicKey)
+ if _, err := io.ReadFull(kdf, arr[:]); err != nil {
+ return nil, errcode.ErrStreamRead.Wrap(err)
+ }
+
+ return &arr, nil
+}
+
+func (m *Group) GetLinkKeyArray() (*[cryptoutil.KeySize]byte, error) {
+ if len(m.GetLinkKey()) == cryptoutil.KeySize {
+ arr := [cryptoutil.KeySize]byte{}
+
+ for i, c := range m.GetLinkKey() {
+ arr[i] = c
+ }
+
+ return &arr, nil
+ }
+
+ return ComputeLinkKey(m.GetPublicKey(), m.GetSecret())
+}
+
+func (m *Group) GetSharedSecret() *[cryptoutil.KeySize]byte {
+ sharedSecret := [cryptoutil.KeySize]byte{}
+ copy(sharedSecret[:], m.GetSecret())
+
+ return &sharedSecret
+}
diff --git a/pkg/protocoltypes/protocoltypes.pb.go b/pkg/protocoltypes/protocoltypes.pb.go
index d0b1c55f..86aae97c 100644
--- a/pkg/protocoltypes/protocoltypes.pb.go
+++ b/pkg/protocoltypes/protocoltypes.pb.go
@@ -67,8 +67,8 @@ const (
EventTypeUndefined EventType = 0
// EventTypeGroupMemberDeviceAdded indicates the payload includes that a member has added their device to the group
EventTypeGroupMemberDeviceAdded EventType = 1
- // EventTypeGroupDeviceSecretAdded indicates the payload includes that a member has sent their device secret to another member
- EventTypeGroupDeviceSecretAdded EventType = 2
+ // EventTypeGroupDeviceChainKeyAdded indicates the payload includes that a member has sent their device chain key to another member
+ EventTypeGroupDeviceChainKeyAdded EventType = 2
// EventTypeAccountGroupJoined indicates the payload includes that the account has joined a group
EventTypeAccountGroupJoined EventType = 101
// EventTypeAccountGroupLeft indicates the payload includes that the account has left a group
@@ -122,7 +122,7 @@ const (
var EventType_name = map[int32]string{
0: "EventTypeUndefined",
1: "EventTypeGroupMemberDeviceAdded",
- 2: "EventTypeGroupDeviceSecretAdded",
+ 2: "EventTypeGroupDeviceChainKeyAdded",
101: "EventTypeAccountGroupJoined",
102: "EventTypeAccountGroupLeft",
103: "EventTypeAccountContactRequestDisabled",
@@ -152,7 +152,7 @@ var EventType_name = map[int32]string{
var EventType_value = map[string]int32{
"EventTypeUndefined": 0,
"EventTypeGroupMemberDeviceAdded": 1,
- "EventTypeGroupDeviceSecretAdded": 2,
+ "EventTypeGroupDeviceChainKeyAdded": 2,
"EventTypeAccountGroupJoined": 101,
"EventTypeAccountGroupLeft": 102,
"EventTypeAccountContactRequestDisabled": 103,
@@ -500,7 +500,7 @@ type Group struct {
Secret []byte `protobuf:"bytes,2,opt,name=secret,proto3" json:"secret,omitempty"`
// secret_sig is the signature of the secret used to ensure the validity of the group
SecretSig []byte `protobuf:"bytes,3,opt,name=secret_sig,json=secretSig,proto3" json:"secret_sig,omitempty"`
- // group_type specifies the type of the group, used to determine how device secrets are generated
+ // group_type specifies the type of the group, used to determine how device chain key is generated
GroupType GroupType `protobuf:"varint,4,opt,name=group_type,json=groupType,proto3,enum=weshnet.protocol.v1.GroupType" json:"group_type,omitempty"`
// sign_pub is the signature public key used to verify entries, not required when secret and secret_sig are provided
SignPub []byte `protobuf:"bytes,5,opt,name=sign_pub,json=signPub,proto3" json:"sign_pub,omitempty"`
@@ -1237,7 +1237,7 @@ func (m *ContactAddAliasKey) GetAliasPK() []byte {
}
// GroupAddMemberDevice is an event which indicates to a group a new device (and eventually a new member) is joining it
-// When added on AccountGroup, this event should be followed by appropriate GroupAddMemberDevice and GroupAddDeviceSecret events
+// When added on AccountGroup, this event should be followed by appropriate GroupAddMemberDevice and GroupAddDeviceChainKey events
type GroupAddMemberDevice struct {
// member_pk is the member sending the event
MemberPK []byte `protobuf:"bytes,1,opt,name=member_pk,json=memberPk,proto3" json:"member_pk,omitempty"`
@@ -1304,8 +1304,8 @@ func (m *GroupAddMemberDevice) GetMemberSig() []byte {
return nil
}
-// DeviceSecret is encrypted for a specific member of the group
-type DeviceSecret struct {
+// DeviceChainKey is a chain key, which will be encrypted for a specific member of the group
+type DeviceChainKey struct {
// chain_key is the current value of the chain key of the group device
ChainKey []byte `protobuf:"bytes,1,opt,name=chain_key,json=chainKey,proto3" json:"chain_key,omitempty"`
// counter is the current value of the counter of the group device
@@ -1315,18 +1315,18 @@ type DeviceSecret struct {
XXX_sizecache int32 `json:"-"`
}
-func (m *DeviceSecret) Reset() { *m = DeviceSecret{} }
-func (m *DeviceSecret) String() string { return proto.CompactTextString(m) }
-func (*DeviceSecret) ProtoMessage() {}
-func (*DeviceSecret) Descriptor() ([]byte, []int) {
+func (m *DeviceChainKey) Reset() { *m = DeviceChainKey{} }
+func (m *DeviceChainKey) String() string { return proto.CompactTextString(m) }
+func (*DeviceChainKey) ProtoMessage() {}
+func (*DeviceChainKey) Descriptor() ([]byte, []int) {
return fileDescriptor_8aa93e54ccb19003, []int{13}
}
-func (m *DeviceSecret) XXX_Unmarshal(b []byte) error {
+func (m *DeviceChainKey) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
-func (m *DeviceSecret) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+func (m *DeviceChainKey) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
- return xxx_messageInfo_DeviceSecret.Marshal(b, m, deterministic)
+ return xxx_messageInfo_DeviceChainKey.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
@@ -1336,34 +1336,34 @@ func (m *DeviceSecret) XXX_Marshal(b []byte, deterministic bool) ([]byte, error)
return b[:n], nil
}
}
-func (m *DeviceSecret) XXX_Merge(src proto.Message) {
- xxx_messageInfo_DeviceSecret.Merge(m, src)
+func (m *DeviceChainKey) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_DeviceChainKey.Merge(m, src)
}
-func (m *DeviceSecret) XXX_Size() int {
+func (m *DeviceChainKey) XXX_Size() int {
return m.Size()
}
-func (m *DeviceSecret) XXX_DiscardUnknown() {
- xxx_messageInfo_DeviceSecret.DiscardUnknown(m)
+func (m *DeviceChainKey) XXX_DiscardUnknown() {
+ xxx_messageInfo_DeviceChainKey.DiscardUnknown(m)
}
-var xxx_messageInfo_DeviceSecret proto.InternalMessageInfo
+var xxx_messageInfo_DeviceChainKey proto.InternalMessageInfo
-func (m *DeviceSecret) GetChainKey() []byte {
+func (m *DeviceChainKey) GetChainKey() []byte {
if m != nil {
return m.ChainKey
}
return nil
}
-func (m *DeviceSecret) GetCounter() uint64 {
+func (m *DeviceChainKey) GetCounter() uint64 {
if m != nil {
return m.Counter
}
return 0
}
-// GroupAddDeviceSecret is an event which indicates to a group member a device secret
-type GroupAddDeviceSecret struct {
+// GroupAddDeviceChainKey is an event which indicates to a group member a device chain key
+type GroupAddDeviceChainKey struct {
// device_pk is the device sending the event, signs the message
DevicePK []byte `protobuf:"bytes,1,opt,name=device_pk,json=devicePk,proto3" json:"device_pk,omitempty"`
// dest_member_pk is the member who should receive the secret
@@ -1375,18 +1375,18 @@ type GroupAddDeviceSecret struct {
XXX_sizecache int32 `json:"-"`
}
-func (m *GroupAddDeviceSecret) Reset() { *m = GroupAddDeviceSecret{} }
-func (m *GroupAddDeviceSecret) String() string { return proto.CompactTextString(m) }
-func (*GroupAddDeviceSecret) ProtoMessage() {}
-func (*GroupAddDeviceSecret) Descriptor() ([]byte, []int) {
+func (m *GroupAddDeviceChainKey) Reset() { *m = GroupAddDeviceChainKey{} }
+func (m *GroupAddDeviceChainKey) String() string { return proto.CompactTextString(m) }
+func (*GroupAddDeviceChainKey) ProtoMessage() {}
+func (*GroupAddDeviceChainKey) Descriptor() ([]byte, []int) {
return fileDescriptor_8aa93e54ccb19003, []int{14}
}
-func (m *GroupAddDeviceSecret) XXX_Unmarshal(b []byte) error {
+func (m *GroupAddDeviceChainKey) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
-func (m *GroupAddDeviceSecret) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+func (m *GroupAddDeviceChainKey) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
- return xxx_messageInfo_GroupAddDeviceSecret.Marshal(b, m, deterministic)
+ return xxx_messageInfo_GroupAddDeviceChainKey.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
@@ -1396,33 +1396,33 @@ func (m *GroupAddDeviceSecret) XXX_Marshal(b []byte, deterministic bool) ([]byte
return b[:n], nil
}
}
-func (m *GroupAddDeviceSecret) XXX_Merge(src proto.Message) {
- xxx_messageInfo_GroupAddDeviceSecret.Merge(m, src)
+func (m *GroupAddDeviceChainKey) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_GroupAddDeviceChainKey.Merge(m, src)
}
-func (m *GroupAddDeviceSecret) XXX_Size() int {
+func (m *GroupAddDeviceChainKey) XXX_Size() int {
return m.Size()
}
-func (m *GroupAddDeviceSecret) XXX_DiscardUnknown() {
- xxx_messageInfo_GroupAddDeviceSecret.DiscardUnknown(m)
+func (m *GroupAddDeviceChainKey) XXX_DiscardUnknown() {
+ xxx_messageInfo_GroupAddDeviceChainKey.DiscardUnknown(m)
}
-var xxx_messageInfo_GroupAddDeviceSecret proto.InternalMessageInfo
+var xxx_messageInfo_GroupAddDeviceChainKey proto.InternalMessageInfo
-func (m *GroupAddDeviceSecret) GetDevicePK() []byte {
+func (m *GroupAddDeviceChainKey) GetDevicePK() []byte {
if m != nil {
return m.DevicePK
}
return nil
}
-func (m *GroupAddDeviceSecret) GetDestMemberPK() []byte {
+func (m *GroupAddDeviceChainKey) GetDestMemberPK() []byte {
if m != nil {
return m.DestMemberPK
}
return nil
}
-func (m *GroupAddDeviceSecret) GetPayload() []byte {
+func (m *GroupAddDeviceChainKey) GetPayload() []byte {
if m != nil {
return m.Payload
}
@@ -1995,7 +1995,7 @@ func (m *AccountContactRequestReferenceReset) GetPublicRendezvousSeed() []byte {
// This event should be followed by an AccountGroupJoined event
// This event should be followed by a GroupAddMemberDevice event within the AccountGroup
-// This event should be followed by a GroupAddDeviceSecret event within the AccountGroup
+// This event should be followed by a GroupAddDeviceChainKey event within the AccountGroup
// AccountContactRequestEnqueued indicates that the account will attempt to send a contact request when a matching peer is discovered
type AccountContactRequestEnqueued struct {
// device_pk is the device sending the event, signs the message
@@ -2267,7 +2267,7 @@ func (m *AccountContactRequestDiscarded) GetContactPK() []byte {
}
// This event should be followed by an AccountGroupJoined event
-// This event should be followed by GroupAddMemberDevice and GroupAddDeviceSecret events within the AccountGroup
+// This event should be followed by GroupAddMemberDevice and GroupAddDeviceChainKey events within the AccountGroup
// AccountContactRequestAccepted indicates that a contact request has been accepted
type AccountContactRequestAccepted struct {
// device_pk is the device sending the event, signs the message
@@ -10048,24 +10048,24 @@ func (m *PushMemberTokenUpdate) GetDevicePK() []byte {
return nil
}
-type PushReceive struct {
+type OutOfStoreReceive struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
-func (m *PushReceive) Reset() { *m = PushReceive{} }
-func (m *PushReceive) String() string { return proto.CompactTextString(m) }
-func (*PushReceive) ProtoMessage() {}
-func (*PushReceive) Descriptor() ([]byte, []int) {
+func (m *OutOfStoreReceive) Reset() { *m = OutOfStoreReceive{} }
+func (m *OutOfStoreReceive) String() string { return proto.CompactTextString(m) }
+func (*OutOfStoreReceive) ProtoMessage() {}
+func (*OutOfStoreReceive) Descriptor() ([]byte, []int) {
return fileDescriptor_8aa93e54ccb19003, []int{91}
}
-func (m *PushReceive) XXX_Unmarshal(b []byte) error {
+func (m *OutOfStoreReceive) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
-func (m *PushReceive) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+func (m *OutOfStoreReceive) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
- return xxx_messageInfo_PushReceive.Marshal(b, m, deterministic)
+ return xxx_messageInfo_OutOfStoreReceive.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
@@ -10075,37 +10075,37 @@ func (m *PushReceive) XXX_Marshal(b []byte, deterministic bool) ([]byte, error)
return b[:n], nil
}
}
-func (m *PushReceive) XXX_Merge(src proto.Message) {
- xxx_messageInfo_PushReceive.Merge(m, src)
+func (m *OutOfStoreReceive) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_OutOfStoreReceive.Merge(m, src)
}
-func (m *PushReceive) XXX_Size() int {
+func (m *OutOfStoreReceive) XXX_Size() int {
return m.Size()
}
-func (m *PushReceive) XXX_DiscardUnknown() {
- xxx_messageInfo_PushReceive.DiscardUnknown(m)
+func (m *OutOfStoreReceive) XXX_DiscardUnknown() {
+ xxx_messageInfo_OutOfStoreReceive.DiscardUnknown(m)
}
-var xxx_messageInfo_PushReceive proto.InternalMessageInfo
+var xxx_messageInfo_OutOfStoreReceive proto.InternalMessageInfo
-type PushReceive_Request struct {
+type OutOfStoreReceive_Request struct {
Payload []byte `protobuf:"bytes,1,opt,name=payload,proto3" json:"payload,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
-func (m *PushReceive_Request) Reset() { *m = PushReceive_Request{} }
-func (m *PushReceive_Request) String() string { return proto.CompactTextString(m) }
-func (*PushReceive_Request) ProtoMessage() {}
-func (*PushReceive_Request) Descriptor() ([]byte, []int) {
+func (m *OutOfStoreReceive_Request) Reset() { *m = OutOfStoreReceive_Request{} }
+func (m *OutOfStoreReceive_Request) String() string { return proto.CompactTextString(m) }
+func (*OutOfStoreReceive_Request) ProtoMessage() {}
+func (*OutOfStoreReceive_Request) Descriptor() ([]byte, []int) {
return fileDescriptor_8aa93e54ccb19003, []int{91, 0}
}
-func (m *PushReceive_Request) XXX_Unmarshal(b []byte) error {
+func (m *OutOfStoreReceive_Request) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
-func (m *PushReceive_Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+func (m *OutOfStoreReceive_Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
- return xxx_messageInfo_PushReceive_Request.Marshal(b, m, deterministic)
+ return xxx_messageInfo_OutOfStoreReceive_Request.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
@@ -10115,26 +10115,26 @@ func (m *PushReceive_Request) XXX_Marshal(b []byte, deterministic bool) ([]byte,
return b[:n], nil
}
}
-func (m *PushReceive_Request) XXX_Merge(src proto.Message) {
- xxx_messageInfo_PushReceive_Request.Merge(m, src)
+func (m *OutOfStoreReceive_Request) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_OutOfStoreReceive_Request.Merge(m, src)
}
-func (m *PushReceive_Request) XXX_Size() int {
+func (m *OutOfStoreReceive_Request) XXX_Size() int {
return m.Size()
}
-func (m *PushReceive_Request) XXX_DiscardUnknown() {
- xxx_messageInfo_PushReceive_Request.DiscardUnknown(m)
+func (m *OutOfStoreReceive_Request) XXX_DiscardUnknown() {
+ xxx_messageInfo_OutOfStoreReceive_Request.DiscardUnknown(m)
}
-var xxx_messageInfo_PushReceive_Request proto.InternalMessageInfo
+var xxx_messageInfo_OutOfStoreReceive_Request proto.InternalMessageInfo
-func (m *PushReceive_Request) GetPayload() []byte {
+func (m *OutOfStoreReceive_Request) GetPayload() []byte {
if m != nil {
return m.Payload
}
return nil
}
-type PushReceive_Reply struct {
+type OutOfStoreReceive_Reply struct {
Message *OutOfStoreMessage `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
Cleartext []byte `protobuf:"bytes,2,opt,name=cleartext,proto3" json:"cleartext,omitempty"`
GroupPublicKey []byte `protobuf:"bytes,3,opt,name=group_public_key,json=groupPublicKey,proto3" json:"group_public_key,omitempty"`
@@ -10144,18 +10144,18 @@ type PushReceive_Reply struct {
XXX_sizecache int32 `json:"-"`
}
-func (m *PushReceive_Reply) Reset() { *m = PushReceive_Reply{} }
-func (m *PushReceive_Reply) String() string { return proto.CompactTextString(m) }
-func (*PushReceive_Reply) ProtoMessage() {}
-func (*PushReceive_Reply) Descriptor() ([]byte, []int) {
+func (m *OutOfStoreReceive_Reply) Reset() { *m = OutOfStoreReceive_Reply{} }
+func (m *OutOfStoreReceive_Reply) String() string { return proto.CompactTextString(m) }
+func (*OutOfStoreReceive_Reply) ProtoMessage() {}
+func (*OutOfStoreReceive_Reply) Descriptor() ([]byte, []int) {
return fileDescriptor_8aa93e54ccb19003, []int{91, 1}
}
-func (m *PushReceive_Reply) XXX_Unmarshal(b []byte) error {
+func (m *OutOfStoreReceive_Reply) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
-func (m *PushReceive_Reply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+func (m *OutOfStoreReceive_Reply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
- return xxx_messageInfo_PushReceive_Reply.Marshal(b, m, deterministic)
+ return xxx_messageInfo_OutOfStoreReceive_Reply.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
@@ -10165,64 +10165,64 @@ func (m *PushReceive_Reply) XXX_Marshal(b []byte, deterministic bool) ([]byte, e
return b[:n], nil
}
}
-func (m *PushReceive_Reply) XXX_Merge(src proto.Message) {
- xxx_messageInfo_PushReceive_Reply.Merge(m, src)
+func (m *OutOfStoreReceive_Reply) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_OutOfStoreReceive_Reply.Merge(m, src)
}
-func (m *PushReceive_Reply) XXX_Size() int {
+func (m *OutOfStoreReceive_Reply) XXX_Size() int {
return m.Size()
}
-func (m *PushReceive_Reply) XXX_DiscardUnknown() {
- xxx_messageInfo_PushReceive_Reply.DiscardUnknown(m)
+func (m *OutOfStoreReceive_Reply) XXX_DiscardUnknown() {
+ xxx_messageInfo_OutOfStoreReceive_Reply.DiscardUnknown(m)
}
-var xxx_messageInfo_PushReceive_Reply proto.InternalMessageInfo
+var xxx_messageInfo_OutOfStoreReceive_Reply proto.InternalMessageInfo
-func (m *PushReceive_Reply) GetMessage() *OutOfStoreMessage {
+func (m *OutOfStoreReceive_Reply) GetMessage() *OutOfStoreMessage {
if m != nil {
return m.Message
}
return nil
}
-func (m *PushReceive_Reply) GetCleartext() []byte {
+func (m *OutOfStoreReceive_Reply) GetCleartext() []byte {
if m != nil {
return m.Cleartext
}
return nil
}
-func (m *PushReceive_Reply) GetGroupPublicKey() []byte {
+func (m *OutOfStoreReceive_Reply) GetGroupPublicKey() []byte {
if m != nil {
return m.GroupPublicKey
}
return nil
}
-func (m *PushReceive_Reply) GetAlreadyReceived() bool {
+func (m *OutOfStoreReceive_Reply) GetAlreadyReceived() bool {
if m != nil {
return m.AlreadyReceived
}
return false
}
-type PushSend struct {
+type OutOfStoreSeal struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
-func (m *PushSend) Reset() { *m = PushSend{} }
-func (m *PushSend) String() string { return proto.CompactTextString(m) }
-func (*PushSend) ProtoMessage() {}
-func (*PushSend) Descriptor() ([]byte, []int) {
+func (m *OutOfStoreSeal) Reset() { *m = OutOfStoreSeal{} }
+func (m *OutOfStoreSeal) String() string { return proto.CompactTextString(m) }
+func (*OutOfStoreSeal) ProtoMessage() {}
+func (*OutOfStoreSeal) Descriptor() ([]byte, []int) {
return fileDescriptor_8aa93e54ccb19003, []int{92}
}
-func (m *PushSend) XXX_Unmarshal(b []byte) error {
+func (m *OutOfStoreSeal) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
-func (m *PushSend) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+func (m *OutOfStoreSeal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
- return xxx_messageInfo_PushSend.Marshal(b, m, deterministic)
+ return xxx_messageInfo_OutOfStoreSeal.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
@@ -10232,188 +10232,38 @@ func (m *PushSend) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return b[:n], nil
}
}
-func (m *PushSend) XXX_Merge(src proto.Message) {
- xxx_messageInfo_PushSend.Merge(m, src)
+func (m *OutOfStoreSeal) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_OutOfStoreSeal.Merge(m, src)
}
-func (m *PushSend) XXX_Size() int {
+func (m *OutOfStoreSeal) XXX_Size() int {
return m.Size()
}
-func (m *PushSend) XXX_DiscardUnknown() {
- xxx_messageInfo_PushSend.DiscardUnknown(m)
+func (m *OutOfStoreSeal) XXX_DiscardUnknown() {
+ xxx_messageInfo_OutOfStoreSeal.DiscardUnknown(m)
}
-var xxx_messageInfo_PushSend proto.InternalMessageInfo
+var xxx_messageInfo_OutOfStoreSeal proto.InternalMessageInfo
-type PushSend_Request struct {
- CID []byte `protobuf:"bytes,1,opt,name=cid,proto3" json:"cid,omitempty"`
- GroupPublicKey []byte `protobuf:"bytes,2,opt,name=group_public_key,json=groupPublicKey,proto3" json:"group_public_key,omitempty"`
- GroupMembers []*MemberWithDevices `protobuf:"bytes,3,rep,name=group_members,json=groupMembers,proto3" json:"group_members,omitempty"`
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
-}
-
-func (m *PushSend_Request) Reset() { *m = PushSend_Request{} }
-func (m *PushSend_Request) String() string { return proto.CompactTextString(m) }
-func (*PushSend_Request) ProtoMessage() {}
-func (*PushSend_Request) Descriptor() ([]byte, []int) {
- return fileDescriptor_8aa93e54ccb19003, []int{92, 0}
-}
-func (m *PushSend_Request) XXX_Unmarshal(b []byte) error {
- return m.Unmarshal(b)
-}
-func (m *PushSend_Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
- if deterministic {
- return xxx_messageInfo_PushSend_Request.Marshal(b, m, deterministic)
- } else {
- b = b[:cap(b)]
- n, err := m.MarshalToSizedBuffer(b)
- if err != nil {
- return nil, err
- }
- return b[:n], nil
- }
-}
-func (m *PushSend_Request) XXX_Merge(src proto.Message) {
- xxx_messageInfo_PushSend_Request.Merge(m, src)
-}
-func (m *PushSend_Request) XXX_Size() int {
- return m.Size()
-}
-func (m *PushSend_Request) XXX_DiscardUnknown() {
- xxx_messageInfo_PushSend_Request.DiscardUnknown(m)
-}
-
-var xxx_messageInfo_PushSend_Request proto.InternalMessageInfo
-
-func (m *PushSend_Request) GetCID() []byte {
- if m != nil {
- return m.CID
- }
- return nil
-}
-
-func (m *PushSend_Request) GetGroupPublicKey() []byte {
- if m != nil {
- return m.GroupPublicKey
- }
- return nil
-}
-
-func (m *PushSend_Request) GetGroupMembers() []*MemberWithDevices {
- if m != nil {
- return m.GroupMembers
- }
- return nil
-}
-
-type PushSend_Reply struct {
- GroupMembers []*MemberWithDevices `protobuf:"bytes,1,rep,name=group_members,json=groupMembers,proto3" json:"group_members,omitempty"`
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
-}
-
-func (m *PushSend_Reply) Reset() { *m = PushSend_Reply{} }
-func (m *PushSend_Reply) String() string { return proto.CompactTextString(m) }
-func (*PushSend_Reply) ProtoMessage() {}
-func (*PushSend_Reply) Descriptor() ([]byte, []int) {
- return fileDescriptor_8aa93e54ccb19003, []int{92, 1}
-}
-func (m *PushSend_Reply) XXX_Unmarshal(b []byte) error {
- return m.Unmarshal(b)
-}
-func (m *PushSend_Reply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
- if deterministic {
- return xxx_messageInfo_PushSend_Reply.Marshal(b, m, deterministic)
- } else {
- b = b[:cap(b)]
- n, err := m.MarshalToSizedBuffer(b)
- if err != nil {
- return nil, err
- }
- return b[:n], nil
- }
-}
-func (m *PushSend_Reply) XXX_Merge(src proto.Message) {
- xxx_messageInfo_PushSend_Reply.Merge(m, src)
-}
-func (m *PushSend_Reply) XXX_Size() int {
- return m.Size()
-}
-func (m *PushSend_Reply) XXX_DiscardUnknown() {
- xxx_messageInfo_PushSend_Reply.DiscardUnknown(m)
-}
-
-var xxx_messageInfo_PushSend_Reply proto.InternalMessageInfo
-
-func (m *PushSend_Reply) GetGroupMembers() []*MemberWithDevices {
- if m != nil {
- return m.GroupMembers
- }
- return nil
-}
-
-type PushShareToken struct {
+type OutOfStoreSeal_Request struct {
+ CID []byte `protobuf:"bytes,1,opt,name=cid,proto3" json:"cid,omitempty"`
+ GroupPublicKey []byte `protobuf:"bytes,2,opt,name=group_public_key,json=groupPublicKey,proto3" json:"group_public_key,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
-func (m *PushShareToken) Reset() { *m = PushShareToken{} }
-func (m *PushShareToken) String() string { return proto.CompactTextString(m) }
-func (*PushShareToken) ProtoMessage() {}
-func (*PushShareToken) Descriptor() ([]byte, []int) {
- return fileDescriptor_8aa93e54ccb19003, []int{93}
-}
-func (m *PushShareToken) XXX_Unmarshal(b []byte) error {
- return m.Unmarshal(b)
-}
-func (m *PushShareToken) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
- if deterministic {
- return xxx_messageInfo_PushShareToken.Marshal(b, m, deterministic)
- } else {
- b = b[:cap(b)]
- n, err := m.MarshalToSizedBuffer(b)
- if err != nil {
- return nil, err
- }
- return b[:n], nil
- }
-}
-func (m *PushShareToken) XXX_Merge(src proto.Message) {
- xxx_messageInfo_PushShareToken.Merge(m, src)
-}
-func (m *PushShareToken) XXX_Size() int {
- return m.Size()
-}
-func (m *PushShareToken) XXX_DiscardUnknown() {
- xxx_messageInfo_PushShareToken.DiscardUnknown(m)
-}
-
-var xxx_messageInfo_PushShareToken proto.InternalMessageInfo
-
-type PushShareToken_Request struct {
- GroupPK []byte `protobuf:"bytes,1,opt,name=group_pk,json=groupPk,proto3" json:"group_pk,omitempty"`
- Server *PushServer `protobuf:"bytes,2,opt,name=server,proto3" json:"server,omitempty"`
- Receiver *PushServiceReceiver `protobuf:"bytes,3,opt,name=receiver,proto3" json:"receiver,omitempty"`
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
-}
-
-func (m *PushShareToken_Request) Reset() { *m = PushShareToken_Request{} }
-func (m *PushShareToken_Request) String() string { return proto.CompactTextString(m) }
-func (*PushShareToken_Request) ProtoMessage() {}
-func (*PushShareToken_Request) Descriptor() ([]byte, []int) {
- return fileDescriptor_8aa93e54ccb19003, []int{93, 0}
+func (m *OutOfStoreSeal_Request) Reset() { *m = OutOfStoreSeal_Request{} }
+func (m *OutOfStoreSeal_Request) String() string { return proto.CompactTextString(m) }
+func (*OutOfStoreSeal_Request) ProtoMessage() {}
+func (*OutOfStoreSeal_Request) Descriptor() ([]byte, []int) {
+ return fileDescriptor_8aa93e54ccb19003, []int{92, 0}
}
-func (m *PushShareToken_Request) XXX_Unmarshal(b []byte) error {
+func (m *OutOfStoreSeal_Request) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
-func (m *PushShareToken_Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+func (m *OutOfStoreSeal_Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
- return xxx_messageInfo_PushShareToken_Request.Marshal(b, m, deterministic)
+ return xxx_messageInfo_OutOfStoreSeal_Request.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
@@ -10423,261 +10273,51 @@ func (m *PushShareToken_Request) XXX_Marshal(b []byte, deterministic bool) ([]by
return b[:n], nil
}
}
-func (m *PushShareToken_Request) XXX_Merge(src proto.Message) {
- xxx_messageInfo_PushShareToken_Request.Merge(m, src)
+func (m *OutOfStoreSeal_Request) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_OutOfStoreSeal_Request.Merge(m, src)
}
-func (m *PushShareToken_Request) XXX_Size() int {
+func (m *OutOfStoreSeal_Request) XXX_Size() int {
return m.Size()
}
-func (m *PushShareToken_Request) XXX_DiscardUnknown() {
- xxx_messageInfo_PushShareToken_Request.DiscardUnknown(m)
-}
-
-var xxx_messageInfo_PushShareToken_Request proto.InternalMessageInfo
-
-func (m *PushShareToken_Request) GetGroupPK() []byte {
- if m != nil {
- return m.GroupPK
- }
- return nil
+func (m *OutOfStoreSeal_Request) XXX_DiscardUnknown() {
+ xxx_messageInfo_OutOfStoreSeal_Request.DiscardUnknown(m)
}
-func (m *PushShareToken_Request) GetServer() *PushServer {
- if m != nil {
- return m.Server
- }
- return nil
-}
+var xxx_messageInfo_OutOfStoreSeal_Request proto.InternalMessageInfo
-func (m *PushShareToken_Request) GetReceiver() *PushServiceReceiver {
+func (m *OutOfStoreSeal_Request) GetCID() []byte {
if m != nil {
- return m.Receiver
+ return m.CID
}
return nil
}
-type PushShareToken_Reply struct {
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
-}
-
-func (m *PushShareToken_Reply) Reset() { *m = PushShareToken_Reply{} }
-func (m *PushShareToken_Reply) String() string { return proto.CompactTextString(m) }
-func (*PushShareToken_Reply) ProtoMessage() {}
-func (*PushShareToken_Reply) Descriptor() ([]byte, []int) {
- return fileDescriptor_8aa93e54ccb19003, []int{93, 1}
-}
-func (m *PushShareToken_Reply) XXX_Unmarshal(b []byte) error {
- return m.Unmarshal(b)
-}
-func (m *PushShareToken_Reply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
- if deterministic {
- return xxx_messageInfo_PushShareToken_Reply.Marshal(b, m, deterministic)
- } else {
- b = b[:cap(b)]
- n, err := m.MarshalToSizedBuffer(b)
- if err != nil {
- return nil, err
- }
- return b[:n], nil
- }
-}
-func (m *PushShareToken_Reply) XXX_Merge(src proto.Message) {
- xxx_messageInfo_PushShareToken_Reply.Merge(m, src)
-}
-func (m *PushShareToken_Reply) XXX_Size() int {
- return m.Size()
-}
-func (m *PushShareToken_Reply) XXX_DiscardUnknown() {
- xxx_messageInfo_PushShareToken_Reply.DiscardUnknown(m)
-}
-
-var xxx_messageInfo_PushShareToken_Reply proto.InternalMessageInfo
-
-type PushSetDeviceToken struct {
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
-}
-
-func (m *PushSetDeviceToken) Reset() { *m = PushSetDeviceToken{} }
-func (m *PushSetDeviceToken) String() string { return proto.CompactTextString(m) }
-func (*PushSetDeviceToken) ProtoMessage() {}
-func (*PushSetDeviceToken) Descriptor() ([]byte, []int) {
- return fileDescriptor_8aa93e54ccb19003, []int{94}
-}
-func (m *PushSetDeviceToken) XXX_Unmarshal(b []byte) error {
- return m.Unmarshal(b)
-}
-func (m *PushSetDeviceToken) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
- if deterministic {
- return xxx_messageInfo_PushSetDeviceToken.Marshal(b, m, deterministic)
- } else {
- b = b[:cap(b)]
- n, err := m.MarshalToSizedBuffer(b)
- if err != nil {
- return nil, err
- }
- return b[:n], nil
- }
-}
-func (m *PushSetDeviceToken) XXX_Merge(src proto.Message) {
- xxx_messageInfo_PushSetDeviceToken.Merge(m, src)
-}
-func (m *PushSetDeviceToken) XXX_Size() int {
- return m.Size()
-}
-func (m *PushSetDeviceToken) XXX_DiscardUnknown() {
- xxx_messageInfo_PushSetDeviceToken.DiscardUnknown(m)
-}
-
-var xxx_messageInfo_PushSetDeviceToken proto.InternalMessageInfo
-
-type PushSetDeviceToken_Request struct {
- Receiver *PushServiceReceiver `protobuf:"bytes,1,opt,name=receiver,proto3" json:"receiver,omitempty"`
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
-}
-
-func (m *PushSetDeviceToken_Request) Reset() { *m = PushSetDeviceToken_Request{} }
-func (m *PushSetDeviceToken_Request) String() string { return proto.CompactTextString(m) }
-func (*PushSetDeviceToken_Request) ProtoMessage() {}
-func (*PushSetDeviceToken_Request) Descriptor() ([]byte, []int) {
- return fileDescriptor_8aa93e54ccb19003, []int{94, 0}
-}
-func (m *PushSetDeviceToken_Request) XXX_Unmarshal(b []byte) error {
- return m.Unmarshal(b)
-}
-func (m *PushSetDeviceToken_Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
- if deterministic {
- return xxx_messageInfo_PushSetDeviceToken_Request.Marshal(b, m, deterministic)
- } else {
- b = b[:cap(b)]
- n, err := m.MarshalToSizedBuffer(b)
- if err != nil {
- return nil, err
- }
- return b[:n], nil
- }
-}
-func (m *PushSetDeviceToken_Request) XXX_Merge(src proto.Message) {
- xxx_messageInfo_PushSetDeviceToken_Request.Merge(m, src)
-}
-func (m *PushSetDeviceToken_Request) XXX_Size() int {
- return m.Size()
-}
-func (m *PushSetDeviceToken_Request) XXX_DiscardUnknown() {
- xxx_messageInfo_PushSetDeviceToken_Request.DiscardUnknown(m)
-}
-
-var xxx_messageInfo_PushSetDeviceToken_Request proto.InternalMessageInfo
-
-func (m *PushSetDeviceToken_Request) GetReceiver() *PushServiceReceiver {
+func (m *OutOfStoreSeal_Request) GetGroupPublicKey() []byte {
if m != nil {
- return m.Receiver
+ return m.GroupPublicKey
}
return nil
}
-type PushSetDeviceToken_Reply struct {
+type OutOfStoreSeal_Reply struct {
+ Encrypted []byte `protobuf:"bytes,1,opt,name=encrypted,proto3" json:"encrypted,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
-func (m *PushSetDeviceToken_Reply) Reset() { *m = PushSetDeviceToken_Reply{} }
-func (m *PushSetDeviceToken_Reply) String() string { return proto.CompactTextString(m) }
-func (*PushSetDeviceToken_Reply) ProtoMessage() {}
-func (*PushSetDeviceToken_Reply) Descriptor() ([]byte, []int) {
- return fileDescriptor_8aa93e54ccb19003, []int{94, 1}
-}
-func (m *PushSetDeviceToken_Reply) XXX_Unmarshal(b []byte) error {
- return m.Unmarshal(b)
-}
-func (m *PushSetDeviceToken_Reply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
- if deterministic {
- return xxx_messageInfo_PushSetDeviceToken_Reply.Marshal(b, m, deterministic)
- } else {
- b = b[:cap(b)]
- n, err := m.MarshalToSizedBuffer(b)
- if err != nil {
- return nil, err
- }
- return b[:n], nil
- }
-}
-func (m *PushSetDeviceToken_Reply) XXX_Merge(src proto.Message) {
- xxx_messageInfo_PushSetDeviceToken_Reply.Merge(m, src)
-}
-func (m *PushSetDeviceToken_Reply) XXX_Size() int {
- return m.Size()
-}
-func (m *PushSetDeviceToken_Reply) XXX_DiscardUnknown() {
- xxx_messageInfo_PushSetDeviceToken_Reply.DiscardUnknown(m)
-}
-
-var xxx_messageInfo_PushSetDeviceToken_Reply proto.InternalMessageInfo
-
-type PushSetServer struct {
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
-}
-
-func (m *PushSetServer) Reset() { *m = PushSetServer{} }
-func (m *PushSetServer) String() string { return proto.CompactTextString(m) }
-func (*PushSetServer) ProtoMessage() {}
-func (*PushSetServer) Descriptor() ([]byte, []int) {
- return fileDescriptor_8aa93e54ccb19003, []int{95}
-}
-func (m *PushSetServer) XXX_Unmarshal(b []byte) error {
- return m.Unmarshal(b)
-}
-func (m *PushSetServer) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
- if deterministic {
- return xxx_messageInfo_PushSetServer.Marshal(b, m, deterministic)
- } else {
- b = b[:cap(b)]
- n, err := m.MarshalToSizedBuffer(b)
- if err != nil {
- return nil, err
- }
- return b[:n], nil
- }
-}
-func (m *PushSetServer) XXX_Merge(src proto.Message) {
- xxx_messageInfo_PushSetServer.Merge(m, src)
-}
-func (m *PushSetServer) XXX_Size() int {
- return m.Size()
-}
-func (m *PushSetServer) XXX_DiscardUnknown() {
- xxx_messageInfo_PushSetServer.DiscardUnknown(m)
-}
-
-var xxx_messageInfo_PushSetServer proto.InternalMessageInfo
-
-type PushSetServer_Request struct {
- Server *PushServer `protobuf:"bytes,1,opt,name=server,proto3" json:"server,omitempty"`
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
-}
-
-func (m *PushSetServer_Request) Reset() { *m = PushSetServer_Request{} }
-func (m *PushSetServer_Request) String() string { return proto.CompactTextString(m) }
-func (*PushSetServer_Request) ProtoMessage() {}
-func (*PushSetServer_Request) Descriptor() ([]byte, []int) {
- return fileDescriptor_8aa93e54ccb19003, []int{95, 0}
+func (m *OutOfStoreSeal_Reply) Reset() { *m = OutOfStoreSeal_Reply{} }
+func (m *OutOfStoreSeal_Reply) String() string { return proto.CompactTextString(m) }
+func (*OutOfStoreSeal_Reply) ProtoMessage() {}
+func (*OutOfStoreSeal_Reply) Descriptor() ([]byte, []int) {
+ return fileDescriptor_8aa93e54ccb19003, []int{92, 1}
}
-func (m *PushSetServer_Request) XXX_Unmarshal(b []byte) error {
+func (m *OutOfStoreSeal_Reply) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
-func (m *PushSetServer_Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+func (m *OutOfStoreSeal_Reply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
- return xxx_messageInfo_PushSetServer_Request.Marshal(b, m, deterministic)
+ return xxx_messageInfo_OutOfStoreSeal_Reply.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
@@ -10687,64 +10327,25 @@ func (m *PushSetServer_Request) XXX_Marshal(b []byte, deterministic bool) ([]byt
return b[:n], nil
}
}
-func (m *PushSetServer_Request) XXX_Merge(src proto.Message) {
- xxx_messageInfo_PushSetServer_Request.Merge(m, src)
+func (m *OutOfStoreSeal_Reply) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_OutOfStoreSeal_Reply.Merge(m, src)
}
-func (m *PushSetServer_Request) XXX_Size() int {
+func (m *OutOfStoreSeal_Reply) XXX_Size() int {
return m.Size()
}
-func (m *PushSetServer_Request) XXX_DiscardUnknown() {
- xxx_messageInfo_PushSetServer_Request.DiscardUnknown(m)
+func (m *OutOfStoreSeal_Reply) XXX_DiscardUnknown() {
+ xxx_messageInfo_OutOfStoreSeal_Reply.DiscardUnknown(m)
}
-var xxx_messageInfo_PushSetServer_Request proto.InternalMessageInfo
+var xxx_messageInfo_OutOfStoreSeal_Reply proto.InternalMessageInfo
-func (m *PushSetServer_Request) GetServer() *PushServer {
+func (m *OutOfStoreSeal_Reply) GetEncrypted() []byte {
if m != nil {
- return m.Server
+ return m.Encrypted
}
return nil
}
-type PushSetServer_Reply struct {
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
-}
-
-func (m *PushSetServer_Reply) Reset() { *m = PushSetServer_Reply{} }
-func (m *PushSetServer_Reply) String() string { return proto.CompactTextString(m) }
-func (*PushSetServer_Reply) ProtoMessage() {}
-func (*PushSetServer_Reply) Descriptor() ([]byte, []int) {
- return fileDescriptor_8aa93e54ccb19003, []int{95, 1}
-}
-func (m *PushSetServer_Reply) XXX_Unmarshal(b []byte) error {
- return m.Unmarshal(b)
-}
-func (m *PushSetServer_Reply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
- if deterministic {
- return xxx_messageInfo_PushSetServer_Reply.Marshal(b, m, deterministic)
- } else {
- b = b[:cap(b)]
- n, err := m.MarshalToSizedBuffer(b)
- if err != nil {
- return nil, err
- }
- return b[:n], nil
- }
-}
-func (m *PushSetServer_Reply) XXX_Merge(src proto.Message) {
- xxx_messageInfo_PushSetServer_Reply.Merge(m, src)
-}
-func (m *PushSetServer_Reply) XXX_Size() int {
- return m.Size()
-}
-func (m *PushSetServer_Reply) XXX_DiscardUnknown() {
- xxx_messageInfo_PushSetServer_Reply.DiscardUnknown(m)
-}
-
-var xxx_messageInfo_PushSetServer_Reply proto.InternalMessageInfo
-
type FirstLastCounters struct {
First uint64 `protobuf:"varint,1,opt,name=first,proto3" json:"first,omitempty"`
Last uint64 `protobuf:"varint,2,opt,name=last,proto3" json:"last,omitempty"`
@@ -10757,7 +10358,7 @@ func (m *FirstLastCounters) Reset() { *m = FirstLastCounters{} }
func (m *FirstLastCounters) String() string { return proto.CompactTextString(m) }
func (*FirstLastCounters) ProtoMessage() {}
func (*FirstLastCounters) Descriptor() ([]byte, []int) {
- return fileDescriptor_8aa93e54ccb19003, []int{96}
+ return fileDescriptor_8aa93e54ccb19003, []int{93}
}
func (m *FirstLastCounters) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -10815,7 +10416,7 @@ func (m *OrbitDBMessageHeads) Reset() { *m = OrbitDBMessageHeads{} }
func (m *OrbitDBMessageHeads) String() string { return proto.CompactTextString(m) }
func (*OrbitDBMessageHeads) ProtoMessage() {}
func (*OrbitDBMessageHeads) Descriptor() ([]byte, []int) {
- return fileDescriptor_8aa93e54ccb19003, []int{97}
+ return fileDescriptor_8aa93e54ccb19003, []int{94}
}
func (m *OrbitDBMessageHeads) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -10872,7 +10473,7 @@ func (m *OrbitDBMessageHeads_Box) Reset() { *m = OrbitDBMessageHeads_Box
func (m *OrbitDBMessageHeads_Box) String() string { return proto.CompactTextString(m) }
func (*OrbitDBMessageHeads_Box) ProtoMessage() {}
func (*OrbitDBMessageHeads_Box) Descriptor() ([]byte, []int) {
- return fileDescriptor_8aa93e54ccb19003, []int{97, 0}
+ return fileDescriptor_8aa93e54ccb19003, []int{94, 0}
}
func (m *OrbitDBMessageHeads_Box) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -10939,7 +10540,7 @@ func (m *RefreshContactRequest) Reset() { *m = RefreshContactRequest{} }
func (m *RefreshContactRequest) String() string { return proto.CompactTextString(m) }
func (*RefreshContactRequest) ProtoMessage() {}
func (*RefreshContactRequest) Descriptor() ([]byte, []int) {
- return fileDescriptor_8aa93e54ccb19003, []int{98}
+ return fileDescriptor_8aa93e54ccb19003, []int{95}
}
func (m *RefreshContactRequest) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -10982,7 +10583,7 @@ func (m *RefreshContactRequest_Peer) Reset() { *m = RefreshContactReques
func (m *RefreshContactRequest_Peer) String() string { return proto.CompactTextString(m) }
func (*RefreshContactRequest_Peer) ProtoMessage() {}
func (*RefreshContactRequest_Peer) Descriptor() ([]byte, []int) {
- return fileDescriptor_8aa93e54ccb19003, []int{98, 0}
+ return fileDescriptor_8aa93e54ccb19003, []int{95, 0}
}
func (m *RefreshContactRequest_Peer) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -11038,7 +10639,7 @@ func (m *RefreshContactRequest_Request) Reset() { *m = RefreshContactReq
func (m *RefreshContactRequest_Request) String() string { return proto.CompactTextString(m) }
func (*RefreshContactRequest_Request) ProtoMessage() {}
func (*RefreshContactRequest_Request) Descriptor() ([]byte, []int) {
- return fileDescriptor_8aa93e54ccb19003, []int{98, 1}
+ return fileDescriptor_8aa93e54ccb19003, []int{95, 1}
}
func (m *RefreshContactRequest_Request) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -11093,7 +10694,7 @@ func (m *RefreshContactRequest_Reply) Reset() { *m = RefreshContactReque
func (m *RefreshContactRequest_Reply) String() string { return proto.CompactTextString(m) }
func (*RefreshContactRequest_Reply) ProtoMessage() {}
func (*RefreshContactRequest_Reply) Descriptor() ([]byte, []int) {
- return fileDescriptor_8aa93e54ccb19003, []int{98, 2}
+ return fileDescriptor_8aa93e54ccb19003, []int{95, 2}
}
func (m *RefreshContactRequest_Reply) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -11153,8 +10754,8 @@ func init() {
proto.RegisterType((*AppMetadata)(nil), "weshnet.protocol.v1.AppMetadata")
proto.RegisterType((*ContactAddAliasKey)(nil), "weshnet.protocol.v1.ContactAddAliasKey")
proto.RegisterType((*GroupAddMemberDevice)(nil), "weshnet.protocol.v1.GroupAddMemberDevice")
- proto.RegisterType((*DeviceSecret)(nil), "weshnet.protocol.v1.DeviceSecret")
- proto.RegisterType((*GroupAddDeviceSecret)(nil), "weshnet.protocol.v1.GroupAddDeviceSecret")
+ proto.RegisterType((*DeviceChainKey)(nil), "weshnet.protocol.v1.DeviceChainKey")
+ proto.RegisterType((*GroupAddDeviceChainKey)(nil), "weshnet.protocol.v1.GroupAddDeviceChainKey")
proto.RegisterType((*MultiMemberGroupAddAliasResolver)(nil), "weshnet.protocol.v1.MultiMemberGroupAddAliasResolver")
proto.RegisterType((*MultiMemberGrantAdminRole)(nil), "weshnet.protocol.v1.MultiMemberGrantAdminRole")
proto.RegisterType((*MultiMemberInitialMember)(nil), "weshnet.protocol.v1.MultiMemberInitialMember")
@@ -11320,21 +10921,12 @@ func init() {
proto.RegisterType((*PushDeviceServerRegistered)(nil), "weshnet.protocol.v1.PushDeviceServerRegistered")
proto.RegisterType((*AccountVerifiedCredentialRegistered)(nil), "weshnet.protocol.v1.AccountVerifiedCredentialRegistered")
proto.RegisterType((*PushMemberTokenUpdate)(nil), "weshnet.protocol.v1.PushMemberTokenUpdate")
- proto.RegisterType((*PushReceive)(nil), "weshnet.protocol.v1.PushReceive")
- proto.RegisterType((*PushReceive_Request)(nil), "weshnet.protocol.v1.PushReceive.Request")
- proto.RegisterType((*PushReceive_Reply)(nil), "weshnet.protocol.v1.PushReceive.Reply")
- proto.RegisterType((*PushSend)(nil), "weshnet.protocol.v1.PushSend")
- proto.RegisterType((*PushSend_Request)(nil), "weshnet.protocol.v1.PushSend.Request")
- proto.RegisterType((*PushSend_Reply)(nil), "weshnet.protocol.v1.PushSend.Reply")
- proto.RegisterType((*PushShareToken)(nil), "weshnet.protocol.v1.PushShareToken")
- proto.RegisterType((*PushShareToken_Request)(nil), "weshnet.protocol.v1.PushShareToken.Request")
- proto.RegisterType((*PushShareToken_Reply)(nil), "weshnet.protocol.v1.PushShareToken.Reply")
- proto.RegisterType((*PushSetDeviceToken)(nil), "weshnet.protocol.v1.PushSetDeviceToken")
- proto.RegisterType((*PushSetDeviceToken_Request)(nil), "weshnet.protocol.v1.PushSetDeviceToken.Request")
- proto.RegisterType((*PushSetDeviceToken_Reply)(nil), "weshnet.protocol.v1.PushSetDeviceToken.Reply")
- proto.RegisterType((*PushSetServer)(nil), "weshnet.protocol.v1.PushSetServer")
- proto.RegisterType((*PushSetServer_Request)(nil), "weshnet.protocol.v1.PushSetServer.Request")
- proto.RegisterType((*PushSetServer_Reply)(nil), "weshnet.protocol.v1.PushSetServer.Reply")
+ proto.RegisterType((*OutOfStoreReceive)(nil), "weshnet.protocol.v1.OutOfStoreReceive")
+ proto.RegisterType((*OutOfStoreReceive_Request)(nil), "weshnet.protocol.v1.OutOfStoreReceive.Request")
+ proto.RegisterType((*OutOfStoreReceive_Reply)(nil), "weshnet.protocol.v1.OutOfStoreReceive.Reply")
+ proto.RegisterType((*OutOfStoreSeal)(nil), "weshnet.protocol.v1.OutOfStoreSeal")
+ proto.RegisterType((*OutOfStoreSeal_Request)(nil), "weshnet.protocol.v1.OutOfStoreSeal.Request")
+ proto.RegisterType((*OutOfStoreSeal_Reply)(nil), "weshnet.protocol.v1.OutOfStoreSeal.Reply")
proto.RegisterType((*FirstLastCounters)(nil), "weshnet.protocol.v1.FirstLastCounters")
proto.RegisterType((*OrbitDBMessageHeads)(nil), "weshnet.protocol.v1.OrbitDBMessageHeads")
proto.RegisterType((*OrbitDBMessageHeads_Box)(nil), "weshnet.protocol.v1.OrbitDBMessageHeads.Box")
@@ -11347,415 +10939,406 @@ func init() {
func init() { proto.RegisterFile("protocoltypes.proto", fileDescriptor_8aa93e54ccb19003) }
var fileDescriptor_8aa93e54ccb19003 = []byte{
- // 6521 bytes of a gzipped FileDescriptorProto
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x7d, 0x5d, 0x6c, 0x1c, 0xd7,
- 0x75, 0xb0, 0x67, 0x97, 0xe4, 0xee, 0x9e, 0x5d, 0x92, 0xc3, 0x2b, 0x4a, 0x5a, 0xad, 0x6d, 0x51,
- 0x1e, 0x59, 0xff, 0x36, 0x25, 0xd3, 0xfe, 0xe2, 0x38, 0x8a, 0x9d, 0x50, 0x24, 0xa5, 0x8f, 0xd6,
- 0xdf, 0x7a, 0x28, 0xc6, 0x71, 0x60, 0x7c, 0x9b, 0xe1, 0xcc, 0xe5, 0x72, 0xc2, 0xd9, 0x99, 0xf1,
- 0xcc, 0x2c, 0x25, 0x06, 0x5f, 0x8a, 0x20, 0x89, 0x93, 0x14, 0x4d, 0xdb, 0xfc, 0x34, 0x45, 0x81,
- 0x04, 0x45, 0x1f, 0xfa, 0x56, 0xa4, 0x2d, 0x8c, 0x22, 0x40, 0x81, 0x3e, 0xf5, 0xa9, 0x29, 0xd2,
- 0x20, 0x4f, 0x79, 0x29, 0xc0, 0xa6, 0x7c, 0x4a, 0x81, 0xa2, 0x68, 0xd1, 0xa4, 0x2f, 0x01, 0x82,
- 0xe2, 0xfe, 0xcd, 0xdc, 0xd9, 0x9d, 0xd9, 0x1f, 0x4a, 0x46, 0x1f, 0xfa, 0xa4, 0xbd, 0x67, 0xce,
- 0xdf, 0x3d, 0xf7, 0xdc, 0x7b, 0xcf, 0x3d, 0xf7, 0x5c, 0x0a, 0x8e, 0xf9, 0x81, 0x17, 0x79, 0xa6,
- 0xe7, 0x44, 0xfb, 0x3e, 0x0e, 0x17, 0x69, 0x0b, 0x1d, 0x7b, 0x88, 0xc3, 0x1d, 0x17, 0x47, 0x8b,
- 0xe2, 0xe3, 0xe2, 0xde, 0x4b, 0x8d, 0xf9, 0xb6, 0xd7, 0xf6, 0x28, 0xe0, 0x2a, 0xf9, 0xc5, 0xbe,
- 0x35, 0x4e, 0xf9, 0xdd, 0x70, 0x87, 0xd2, 0x5e, 0x8d, 0x7f, 0xb1, 0x4f, 0xda, 0x3f, 0x28, 0x50,
- 0x5a, 0x36, 0x4d, 0xaf, 0xeb, 0x46, 0xe8, 0x1a, 0x4c, 0xb6, 0x03, 0xaf, 0xeb, 0xd7, 0x95, 0x33,
- 0xca, 0xc5, 0xea, 0x52, 0x63, 0x31, 0x43, 0xc2, 0xe2, 0x2d, 0x82, 0xa1, 0x33, 0x44, 0xb4, 0x08,
- 0xc7, 0x0c, 0x46, 0xdc, 0xf2, 0x03, 0x7b, 0xcf, 0x88, 0x70, 0x6b, 0x17, 0xef, 0xd7, 0x0b, 0x67,
- 0x94, 0x8b, 0x35, 0x7d, 0x8e, 0x7f, 0x6a, 0xb2, 0x2f, 0xb7, 0xf1, 0x3e, 0xba, 0x0c, 0x73, 0x86,
- 0x63, 0x1b, 0x61, 0x0a, 0xbb, 0x48, 0xb1, 0x67, 0xe9, 0x07, 0x09, 0xf7, 0x15, 0x38, 0xe1, 0x77,
- 0xb7, 0x1c, 0xdb, 0x6c, 0x05, 0xd8, 0xb5, 0xf0, 0xe7, 0xf7, 0xbc, 0x6e, 0xd8, 0x0a, 0x31, 0xb6,
- 0xea, 0x13, 0x94, 0x60, 0x9e, 0x7d, 0xd5, 0xe3, 0x8f, 0x1b, 0x18, 0x5b, 0xda, 0x2f, 0x15, 0x98,
- 0xa4, 0x2a, 0xa2, 0x67, 0x01, 0x38, 0x3d, 0x11, 0xa2, 0x50, 0x9a, 0x0a, 0x83, 0x10, 0xf6, 0x27,
- 0x60, 0x2a, 0xc4, 0x66, 0x80, 0x23, 0xae, 0x2d, 0x6f, 0x11, 0x32, 0xf6, 0xab, 0x15, 0xda, 0x6d,
- 0xae, 0x5b, 0x85, 0x41, 0x36, 0xec, 0x36, 0x7a, 0x1d, 0x80, 0x76, 0xbd, 0x45, 0x8c, 0x48, 0x35,
- 0x99, 0x59, 0x3a, 0x9d, 0x6f, 0xa8, 0x07, 0xfb, 0x3e, 0xd6, 0x2b, 0x6d, 0xf1, 0x13, 0x9d, 0x82,
- 0x72, 0x68, 0xb7, 0xdd, 0x96, 0xdf, 0xdd, 0xaa, 0x4f, 0x52, 0xde, 0x25, 0xd2, 0x6e, 0x76, 0xb7,
- 0xc8, 0x27, 0xc7, 0x76, 0x77, 0xa9, 0xb6, 0x53, 0xec, 0x13, 0x69, 0x13, 0x5d, 0xcf, 0x40, 0x4d,
- 0x7c, 0xa2, 0x5a, 0x95, 0xe8, 0x67, 0xe0, 0x9f, 0x37, 0xec, 0xb6, 0xf6, 0x2b, 0x05, 0x54, 0x2a,
- 0xf0, 0xff, 0x62, 0xc3, 0x0a, 0xd7, 0x1e, 0xf9, 0x5e, 0x10, 0x0d, 0xb3, 0x80, 0xac, 0x4b, 0x21,
- 0xad, 0xcb, 0x1a, 0x1c, 0xeb, 0xe0, 0xc8, 0xb0, 0x8c, 0xc8, 0x68, 0xed, 0x10, 0x8e, 0x2d, 0xd3,
- 0xb6, 0xc2, 0x7a, 0xf1, 0x4c, 0xf1, 0x62, 0xed, 0xc6, 0xf1, 0xc3, 0x83, 0x85, 0xb9, 0xbb, 0xfc,
- 0x33, 0x95, 0xb7, 0xb2, 0xbe, 0x1a, 0xea, 0x73, 0x9d, 0x14, 0xc8, 0xb6, 0x42, 0xc6, 0x26, 0x0c,
- 0x8d, 0x36, 0x0e, 0x65, 0x36, 0x13, 0x32, 0x1b, 0xf6, 0x39, 0xc5, 0x46, 0x06, 0x11, 0x36, 0xb2,
- 0x65, 0x26, 0x53, 0x96, 0xd1, 0x7e, 0xa2, 0xc0, 0x34, 0xed, 0xb7, 0xd0, 0x87, 0x0c, 0x10, 0xde,
- 0xc3, 0x6e, 0xc4, 0x06, 0x48, 0x19, 0x30, 0x40, 0x6b, 0x04, 0x8d, 0x0d, 0x10, 0x16, 0x3f, 0x51,
- 0x1d, 0x4a, 0xbe, 0xb1, 0xef, 0x78, 0x86, 0x25, 0x6c, 0xc2, 0x9b, 0x48, 0x85, 0x62, 0xe2, 0x11,
- 0xe4, 0x27, 0xd2, 0x61, 0x4e, 0xf0, 0x6b, 0x89, 0xce, 0x53, 0x97, 0xa8, 0x2e, 0x9d, 0xcb, 0x94,
- 0xd8, 0xe4, 0xbf, 0x85, 0xb2, 0xba, 0xea, 0xf7, 0x40, 0xb4, 0x65, 0xde, 0x9f, 0x35, 0x77, 0x0f,
- 0x3b, 0x9e, 0x8f, 0xd1, 0x3c, 0x4c, 0xba, 0x9e, 0x6b, 0x62, 0x3e, 0x7e, 0xac, 0x41, 0xa0, 0x54,
- 0x67, 0xae, 0x24, 0x6b, 0xbc, 0x39, 0x51, 0x2e, 0xaa, 0x13, 0xda, 0x7f, 0x2a, 0x30, 0xc3, 0xed,
- 0x4a, 0x6c, 0x88, 0x83, 0x90, 0xf4, 0x8a, 0x4e, 0x45, 0x1c, 0x50, 0x36, 0x13, 0xba, 0x68, 0xa2,
- 0x4b, 0x50, 0xb1, 0xf0, 0x9e, 0x6d, 0xe2, 0x96, 0xbf, 0xcb, 0x98, 0xdd, 0xa8, 0x1d, 0x1e, 0x2c,
- 0x94, 0x57, 0x29, 0xb0, 0x79, 0x5b, 0x2f, 0xb3, 0xcf, 0xcd, 0xdd, 0x0c, 0x03, 0xdc, 0x85, 0xb2,
- 0xd4, 0xef, 0xe2, 0xc5, 0xea, 0xd2, 0x4b, 0x99, 0xfd, 0x4e, 0x6b, 0xb3, 0x28, 0x3a, 0xbb, 0xe6,
- 0x46, 0xc1, 0xbe, 0x1e, 0xb3, 0x68, 0x5c, 0x87, 0xe9, 0xd4, 0x27, 0x22, 0x51, 0x78, 0x6e, 0x45,
- 0x27, 0x3f, 0x49, 0xbf, 0xf7, 0x0c, 0xa7, 0x8b, 0xa9, 0xaa, 0x15, 0x9d, 0x35, 0x3e, 0x56, 0xf8,
- 0xa8, 0xa2, 0xd5, 0x41, 0xed, 0x35, 0xef, 0x9b, 0x13, 0x65, 0x45, 0x2d, 0x68, 0x5f, 0x51, 0x40,
- 0x5d, 0x73, 0xcd, 0x60, 0xdf, 0x8f, 0xb0, 0xc5, 0x55, 0x41, 0xcf, 0x40, 0xc5, 0x77, 0x0c, 0xdb,
- 0x8d, 0xf0, 0xa3, 0x28, 0x9e, 0x1a, 0x02, 0x90, 0x3d, 0xb2, 0x85, 0xc7, 0x1b, 0x59, 0x1f, 0x66,
- 0xb9, 0xf0, 0x78, 0x6c, 0x2f, 0xc0, 0x2c, 0xf7, 0x76, 0x3a, 0x3d, 0x70, 0x10, 0x72, 0x55, 0x66,
- 0x3a, 0x7d, 0xe3, 0xc7, 0x21, 0xc2, 0x2b, 0x79, 0x33, 0x71, 0x8f, 0xa2, 0xe4, 0x1e, 0x6f, 0x4e,
- 0x94, 0x27, 0xd4, 0x49, 0xed, 0x4b, 0x0a, 0xd4, 0xa8, 0x93, 0xaf, 0x78, 0xac, 0x5b, 0x27, 0xa0,
- 0x60, 0x5b, 0x4c, 0xc4, 0x8d, 0xa9, 0xc3, 0x83, 0x85, 0xc2, 0xfa, 0xaa, 0x5e, 0xb0, 0x2d, 0xf4,
- 0x02, 0x80, 0x6f, 0x04, 0x64, 0xd2, 0x90, 0xe9, 0x59, 0xa0, 0xd3, 0x73, 0xfa, 0xf0, 0x60, 0xa1,
- 0xd2, 0xa4, 0x50, 0x32, 0x2d, 0x2b, 0x0c, 0x61, 0xdd, 0x0a, 0xd1, 0x79, 0x28, 0xb3, 0x25, 0xd0,
- 0xdf, 0x65, 0x52, 0x6f, 0x54, 0x0f, 0x0f, 0x16, 0x4a, 0xd4, 0x6d, 0x9b, 0xb7, 0xf5, 0x12, 0xfd,
- 0xd8, 0xdc, 0xe5, 0x4a, 0xe8, 0x50, 0x5d, 0xf6, 0x93, 0xe9, 0x99, 0xf2, 0x37, 0x65, 0xa0, 0xbf,
- 0xe5, 0x76, 0x5a, 0x6b, 0x03, 0x22, 0x5d, 0x32, 0xcc, 0x68, 0xd9, 0xb2, 0x96, 0xc9, 0xbe, 0x41,
- 0xd6, 0xb3, 0x31, 0x58, 0x9f, 0x87, 0x32, 0xdf, 0x87, 0x84, 0xd3, 0xd3, 0x2e, 0x50, 0x56, 0xa4,
- 0x0b, 0x6c, 0x2f, 0xda, 0xd5, 0x7e, 0x47, 0x81, 0x79, 0xda, 0xaf, 0x65, 0xcb, 0xba, 0x8b, 0x3b,
- 0x5b, 0x38, 0x60, 0xcc, 0x88, 0xac, 0x0e, 0x6d, 0xf7, 0xc8, 0x62, 0x48, 0x44, 0x16, 0xfb, 0xdc,
- 0xdc, 0x1d, 0x67, 0x86, 0x3d, 0x0b, 0xc0, 0xb9, 0x4a, 0x7b, 0x0f, 0x83, 0x90, 0x45, 0x7e, 0x0d,
- 0x6a, 0x8c, 0x68, 0x83, 0x6d, 0x55, 0x4f, 0x43, 0xc5, 0xdc, 0x31, 0x6c, 0x57, 0x5a, 0xde, 0xcb,
- 0x14, 0x40, 0xac, 0x21, 0x4d, 0xf9, 0x42, 0x6a, 0xca, 0x6b, 0xdf, 0x91, 0x3a, 0x95, 0xe2, 0x37,
- 0x86, 0x01, 0x3f, 0x02, 0x33, 0x16, 0x0e, 0xa3, 0x56, 0x62, 0x04, 0xd6, 0x33, 0xf5, 0xf0, 0x60,
- 0xa1, 0xb6, 0x8a, 0xc3, 0x28, 0x36, 0x44, 0xcd, 0x4a, 0x5a, 0xbb, 0xf2, 0xf2, 0x5a, 0x4c, 0x2d,
- 0xaf, 0xda, 0x77, 0x15, 0x38, 0x73, 0xb7, 0xeb, 0x44, 0x36, 0xc3, 0x15, 0x0a, 0xd2, 0x21, 0xd1,
- 0x71, 0xe8, 0x39, 0x7b, 0xbd, 0xab, 0xd5, 0x60, 0x0d, 0xcf, 0xc1, 0x0c, 0x1b, 0xe2, 0x80, 0x13,
- 0x73, 0x27, 0x9a, 0x36, 0x52, 0x1c, 0x17, 0xa0, 0x2a, 0x22, 0x12, 0xcf, 0xdb, 0xe6, 0x4a, 0x01,
- 0x8f, 0x45, 0x3c, 0x6f, 0x5b, 0xfb, 0x9a, 0x02, 0xa7, 0x52, 0x7a, 0x19, 0x6e, 0xb4, 0x6c, 0x75,
- 0x6c, 0x57, 0xf7, 0x1c, 0x3c, 0x8e, 0x42, 0x9f, 0x80, 0xb9, 0x36, 0x21, 0xc6, 0xb8, 0xcf, 0x6a,
- 0xc7, 0x0e, 0x0f, 0x16, 0x66, 0x6f, 0xb1, 0x8f, 0xb1, 0xe1, 0x66, 0xdb, 0x29, 0xc0, 0xae, 0xb6,
- 0x06, 0x75, 0x49, 0x91, 0x75, 0xd7, 0x8e, 0x6c, 0xc3, 0x61, 0x8d, 0x31, 0xfc, 0x51, 0x33, 0xe0,
- 0x4c, 0x6c, 0x5c, 0xcb, 0xb2, 0x23, 0xdb, 0x73, 0x0d, 0x27, 0x1d, 0x45, 0x8d, 0xd3, 0x2d, 0x04,
- 0x13, 0x34, 0x28, 0x63, 0xd6, 0xa5, 0xbf, 0x35, 0x0b, 0xce, 0xb2, 0x30, 0x11, 0x77, 0xbc, 0x3d,
- 0xfc, 0x61, 0x49, 0x79, 0x0f, 0x10, 0x8f, 0x5c, 0xa9, 0xb0, 0x37, 0x3d, 0xdb, 0x1d, 0x8f, 0x69,
- 0x1c, 0xef, 0x16, 0x46, 0x8c, 0x77, 0x35, 0x0c, 0xaa, 0x2c, 0xf2, 0x0e, 0xde, 0x8e, 0xc6, 0x5c,
- 0x76, 0xe2, 0x95, 0xb3, 0x90, 0xbf, 0x72, 0x6a, 0x6f, 0xc2, 0xb3, 0x5c, 0x0c, 0x5f, 0xe6, 0x74,
- 0xfc, 0x5e, 0x17, 0x87, 0xd1, 0xaa, 0x1d, 0x1a, 0x5b, 0xce, 0x58, 0x9d, 0xd4, 0xd6, 0xe1, 0x99,
- 0x4c, 0x5e, 0x6b, 0xee, 0xd8, 0xac, 0xbe, 0xaa, 0xc0, 0xd9, 0x4c, 0x5e, 0x3a, 0xde, 0xc6, 0x01,
- 0x76, 0x4d, 0xac, 0xe3, 0x70, 0xbc, 0x75, 0x24, 0x3f, 0xc8, 0x2f, 0x0c, 0x08, 0xf2, 0x7f, 0xa6,
- 0xe4, 0x18, 0x68, 0xcd, 0x7d, 0xaf, 0x8b, 0xbb, 0xe3, 0x79, 0xc1, 0x88, 0x83, 0x82, 0x3e, 0x41,
- 0x16, 0x54, 0x2a, 0x8c, 0xae, 0x12, 0x79, 0x91, 0xc0, 0xc6, 0x8e, 0x11, 0x60, 0x62, 0x5a, 0xa1,
- 0x99, 0xa0, 0x42, 0xcf, 0x41, 0xcd, 0x7b, 0xe8, 0xa6, 0x23, 0xc5, 0x9a, 0x5e, 0xf5, 0x1e, 0xba,
- 0x71, 0x8c, 0x10, 0xc1, 0xa9, 0xcc, 0x7e, 0x6d, 0x60, 0x77, 0x2c, 0xb3, 0xbe, 0x00, 0xc0, 0xa5,
- 0x26, 0xbd, 0xa2, 0x1b, 0x3a, 0x67, 0xdb, 0xbc, 0xad, 0x57, 0x38, 0x42, 0x73, 0x57, 0xfb, 0xc7,
- 0x3c, 0x73, 0xea, 0xd8, 0xc4, 0xf6, 0xde, 0x78, 0xe6, 0x1c, 0x4b, 0x34, 0xfa, 0x08, 0x9c, 0x14,
- 0xd8, 0xbd, 0x0e, 0xc0, 0x96, 0xe2, 0xe3, 0xa6, 0xd0, 0xa8, 0x67, 0xe9, 0x50, 0x05, 0x5d, 0x8f,
- 0x3d, 0x67, 0x39, 0x3c, 0xb6, 0xe9, 0x3e, 0x9c, 0xce, 0x9b, 0x4c, 0xa6, 0x11, 0x58, 0x1f, 0x62,
- 0xef, 0xb4, 0x3f, 0xc9, 0x33, 0xec, 0xb2, 0x69, 0x62, 0x12, 0x8d, 0x7e, 0x78, 0x86, 0x1d, 0x31,
- 0x48, 0xd3, 0x7c, 0x38, 0x9e, 0xd6, 0xf0, 0x86, 0xe3, 0x99, 0xbb, 0x1f, 0xa6, 0x51, 0x02, 0x38,
- 0x99, 0x96, 0xb8, 0xe9, 0x6e, 0x7d, 0xd8, 0x32, 0x7f, 0x57, 0x81, 0x3a, 0x17, 0xba, 0x81, 0x03,
- 0xc2, 0xe2, 0x81, 0xb7, 0x8b, 0xdd, 0x65, 0x6b, 0xcc, 0xe1, 0xbf, 0x09, 0xd3, 0x21, 0xa3, 0x6f,
- 0x45, 0x84, 0x01, 0xdf, 0x39, 0x9e, 0xcb, 0x5e, 0x09, 0x24, 0x49, 0x7a, 0x2d, 0x94, 0x5a, 0x9a,
- 0x07, 0x8d, 0x0c, 0x75, 0xd8, 0x76, 0x39, 0xee, 0xe2, 0x45, 0x15, 0x69, 0xd9, 0x6c, 0xc5, 0xac,
- 0xb0, 0x61, 0xa6, 0xec, 0xd6, 0x57, 0xf5, 0x12, 0xfd, 0xb8, 0x6e, 0x69, 0x1f, 0x88, 0xfc, 0x80,
- 0x8e, 0x7d, 0xc7, 0x36, 0x8d, 0xc8, 0x76, 0xdb, 0xe3, 0xc8, 0x59, 0x05, 0x64, 0x74, 0xa3, 0x1d,
- 0xec, 0x46, 0x94, 0xd8, 0x73, 0x5b, 0xdd, 0xc0, 0xe1, 0x12, 0xe9, 0x41, 0x7e, 0x39, 0xf5, 0x75,
- 0x53, 0xbf, 0xa3, 0xcf, 0xa5, 0x09, 0x36, 0x03, 0x07, 0xbd, 0x08, 0x28, 0x10, 0xf2, 0x3d, 0xb7,
- 0x45, 0x4c, 0x82, 0x03, 0xea, 0x9e, 0x15, 0x7d, 0x4e, 0xfa, 0xb2, 0x41, 0x3f, 0x68, 0x77, 0x60,
- 0x8e, 0x9b, 0x87, 0x25, 0x34, 0x56, 0xc9, 0x21, 0xb1, 0x02, 0x25, 0x3e, 0x89, 0x1a, 0x2f, 0xc0,
- 0x24, 0xe9, 0xce, 0x3e, 0x3a, 0x0b, 0xd3, 0x98, 0x62, 0x60, 0xab, 0x45, 0x97, 0x02, 0x16, 0x0c,
- 0xd7, 0x04, 0x90, 0x10, 0x6a, 0xbf, 0x9a, 0x82, 0x93, 0x9c, 0xdd, 0x2d, 0x4c, 0x7c, 0x6f, 0xdb,
- 0x6e, 0x77, 0x03, 0x2a, 0x4f, 0x66, 0xfa, 0xfe, 0x94, 0xe0, 0xfa, 0x02, 0x40, 0x9c, 0xdc, 0x12,
- 0xf6, 0xa1, 0x2e, 0xc6, 0x87, 0x8e, 0xb8, 0x98, 0x48, 0x71, 0x8d, 0x15, 0xe6, 0x7f, 0x1c, 0x54,
- 0xc1, 0xb8, 0x67, 0x8e, 0xa2, 0xc3, 0x83, 0x85, 0x19, 0x39, 0xc2, 0x68, 0xde, 0xd6, 0x67, 0x0c,
- 0xb9, 0xbd, 0x8b, 0xce, 0x42, 0xc9, 0xc7, 0x38, 0x20, 0x23, 0x3e, 0x41, 0xed, 0x0f, 0x87, 0x07,
- 0x0b, 0x53, 0x4d, 0x8c, 0x83, 0xf5, 0x55, 0x7d, 0x8a, 0x7c, 0x5a, 0xb7, 0xc8, 0xf1, 0xd6, 0xb1,
- 0xc3, 0x08, 0xbb, 0xe4, 0x4c, 0x39, 0x79, 0xa6, 0x78, 0xb1, 0xa2, 0x27, 0x00, 0xf4, 0x19, 0xa8,
- 0x6e, 0x39, 0xb8, 0x85, 0x59, 0x08, 0x40, 0xb3, 0x4d, 0x33, 0x4b, 0xaf, 0x0d, 0x72, 0xe2, 0x5e,
- 0x8b, 0x2d, 0x6e, 0xe0, 0x88, 0xf8, 0xd0, 0x46, 0x64, 0x44, 0x58, 0x87, 0x2d, 0x07, 0x8b, 0x78,
- 0xc2, 0x04, 0xf5, 0xa1, 0xbd, 0x6d, 0xb7, 0xfc, 0x25, 0x3f, 0x16, 0x50, 0x7a, 0x5c, 0x01, 0x33,
- 0x84, 0x65, 0x73, 0xc9, 0x17, 0x42, 0xde, 0x85, 0x5a, 0xc7, 0x72, 0xc3, 0x58, 0x40, 0xf9, 0x71,
- 0x05, 0x54, 0x09, 0x3b, 0xc1, 0xfd, 0xff, 0xc1, 0x74, 0x80, 0x1d, 0x63, 0x3f, 0x66, 0x5f, 0x79,
- 0x5c, 0xf6, 0x35, 0xca, 0x4f, 0xf0, 0x7f, 0x00, 0x73, 0xc2, 0x55, 0xba, 0xe1, 0x0e, 0x5f, 0x49,
- 0x80, 0xae, 0x24, 0x17, 0xb3, 0xb3, 0x0b, 0xdd, 0x70, 0x87, 0xcb, 0xe1, 0x5b, 0x72, 0xa0, 0xcf,
- 0x72, 0x77, 0xea, 0x86, 0x3b, 0x74, 0xb6, 0xa3, 0xbb, 0x80, 0x64, 0xae, 0x7c, 0x72, 0x55, 0x29,
- 0xdb, 0x85, 0x81, 0x6c, 0x71, 0xa0, 0xab, 0x09, 0x37, 0x3e, 0xf9, 0x6e, 0x41, 0x4d, 0xee, 0x02,
- 0xaa, 0x42, 0x69, 0xd3, 0xdd, 0x75, 0xbd, 0x87, 0xae, 0xfa, 0x14, 0x69, 0xf0, 0xce, 0xa8, 0x0a,
- 0xaa, 0x41, 0x59, 0x04, 0xa6, 0x6a, 0x01, 0xcd, 0x42, 0x75, 0xd3, 0x35, 0xf6, 0x0c, 0xdb, 0x21,
- 0x10, 0xb5, 0xa8, 0x7d, 0x01, 0x4e, 0xe6, 0x44, 0x8b, 0xf2, 0xb4, 0x7b, 0x5b, 0xcc, 0xba, 0xfc,
- 0x88, 0x50, 0xc9, 0x8f, 0x08, 0xc9, 0xb9, 0x52, 0x0c, 0x16, 0x99, 0x7b, 0x65, 0x5d, 0x34, 0xb5,
- 0x2b, 0x70, 0x3c, 0x33, 0x88, 0x96, 0x85, 0x97, 0xb8, 0x70, 0xed, 0xb3, 0x30, 0x9f, 0x15, 0x25,
- 0xcb, 0xb8, 0xaf, 0x3f, 0x96, 0xa2, 0xda, 0x0e, 0x3c, 0xd3, 0x6b, 0x8d, 0x10, 0x67, 0x9b, 0xe4,
- 0x31, 0x25, 0x7d, 0x43, 0x89, 0xb3, 0x24, 0x49, 0x14, 0x69, 0x35, 0x3a, 0xb1, 0x00, 0x39, 0xa2,
- 0x55, 0x9e, 0x48, 0x44, 0x5b, 0xe8, 0x8b, 0x68, 0x13, 0xd3, 0x7e, 0xba, 0xd7, 0xb4, 0x2c, 0x06,
- 0x6a, 0xbc, 0x9a, 0xe8, 0x93, 0xde, 0xd3, 0x95, 0xc1, 0x7b, 0x7a, 0xc2, 0xf9, 0x9d, 0x8c, 0x11,
- 0x26, 0x91, 0xdd, 0x13, 0x60, 0xdd, 0x84, 0x9a, 0x1c, 0x16, 0x3d, 0x01, 0x8e, 0x3a, 0xcc, 0xa4,
- 0xc3, 0x9e, 0x27, 0xc0, 0xf3, 0x2d, 0x38, 0x26, 0xd2, 0x61, 0x3c, 0x17, 0x46, 0x47, 0xfa, 0xa5,
- 0x84, 0xb1, 0x1c, 0x0d, 0x2a, 0xf9, 0xd1, 0x60, 0xc2, 0xf2, 0x01, 0x9c, 0xe8, 0x4d, 0xc6, 0xac,
- 0x04, 0xd8, 0x88, 0x52, 0x0e, 0x7a, 0x55, 0x38, 0xe8, 0x88, 0xec, 0xb5, 0x77, 0x61, 0xbe, 0x97,
- 0x2b, 0x39, 0xb5, 0x37, 0xae, 0x27, 0x9a, 0x8e, 0x7d, 0x07, 0x95, 0xe8, 0xbc, 0x01, 0xc7, 0x7b,
- 0xb9, 0xdf, 0xc1, 0xc6, 0x1e, 0x7e, 0x2c, 0x43, 0x98, 0x70, 0xae, 0x2f, 0x2b, 0x25, 0x27, 0x90,
- 0x88, 0xaf, 0x39, 0x5e, 0xf8, 0x78, 0x42, 0xbe, 0xa6, 0xc0, 0xe9, 0xfe, 0xdc, 0x17, 0xcf, 0x31,
- 0xd1, 0xbc, 0x50, 0xe3, 0xdd, 0xb1, 0xd9, 0xa7, 0x73, 0x42, 0x85, 0x41, 0x39, 0xa1, 0x44, 0x93,
- 0x6f, 0x66, 0x64, 0xe1, 0xd6, 0xdd, 0x3d, 0x3b, 0xa2, 0x9b, 0x1a, 0x77, 0x81, 0x23, 0x74, 0xf5,
- 0x35, 0xe1, 0x2a, 0x63, 0x8f, 0xaf, 0xf6, 0x75, 0x05, 0x66, 0xa5, 0x0c, 0x32, 0x75, 0xed, 0xb7,
- 0xc6, 0xb7, 0x46, 0xee, 0xc5, 0x0e, 0xbb, 0x35, 0x69, 0x68, 0x42, 0xc3, 0x53, 0x50, 0x34, 0xe3,
- 0x2c, 0x79, 0xe9, 0xf0, 0x60, 0xa1, 0xb8, 0xb2, 0xbe, 0xaa, 0x13, 0x18, 0x19, 0xa7, 0x19, 0xaa,
- 0x0a, 0x4d, 0x43, 0xff, 0x4f, 0x6a, 0xf2, 0x81, 0x02, 0x28, 0x75, 0xef, 0x45, 0xf3, 0xfc, 0xe4,
- 0x7c, 0xc2, 0x2e, 0xbf, 0x4c, 0x2f, 0xb9, 0xd9, 0xc8, 0x3b, 0x9f, 0xc8, 0x57, 0x03, 0x7a, 0x0d,
- 0xcb, 0x17, 0x05, 0x6f, 0x48, 0x17, 0x3b, 0xec, 0x88, 0xa3, 0xe5, 0x0f, 0x54, 0x7c, 0xe7, 0x11,
- 0xd3, 0x24, 0xd7, 0x53, 0x45, 0xe9, 0x7a, 0x4a, 0xfb, 0x2b, 0x05, 0xe6, 0x38, 0x05, 0xbb, 0x07,
- 0x79, 0xa2, 0x3a, 0xbf, 0x0e, 0x25, 0x71, 0x89, 0xc2, 0x54, 0x3e, 0x3b, 0xc2, 0x5d, 0x94, 0x2e,
- 0x68, 0xe4, 0xdb, 0x86, 0x62, 0xfa, 0xb6, 0xe1, 0xbf, 0x12, 0xb5, 0x59, 0xf7, 0xee, 0xd8, 0x61,
- 0xd4, 0xf8, 0xb9, 0x32, 0xfe, 0xc8, 0x9f, 0x87, 0x72, 0x68, 0xbb, 0x26, 0x16, 0xa7, 0x35, 0x8e,
- 0xb7, 0x41, 0x60, 0xe4, 0xb4, 0x46, 0x3f, 0xae, 0x5b, 0xe8, 0x69, 0xa8, 0x30, 0x3c, 0xd7, 0x7b,
- 0x48, 0xb5, 0x29, 0xeb, 0x8c, 0xf0, 0x9e, 0xf7, 0x90, 0x30, 0xe9, 0xba, 0x91, 0xed, 0x88, 0x03,
- 0x00, 0x67, 0xb2, 0x49, 0x60, 0x84, 0x09, 0xfd, 0xc8, 0x98, 0x30, 0x3c, 0xc2, 0x64, 0x92, 0x31,
- 0xa1, 0x00, 0xc2, 0xe4, 0x2c, 0x09, 0x71, 0xf7, 0x70, 0x10, 0xe2, 0x96, 0x17, 0x58, 0x38, 0xa0,
- 0x67, 0x80, 0x32, 0x89, 0x53, 0x29, 0xf0, 0x3e, 0x81, 0x25, 0x97, 0xca, 0xdc, 0x66, 0xff, 0x5b,
- 0xfa, 0xfd, 0x1b, 0x05, 0x2a, 0x7c, 0xe5, 0xdb, 0xf6, 0x1a, 0xad, 0xf1, 0xfb, 0x3b, 0x56, 0x72,
- 0xa2, 0xf1, 0xfb, 0xca, 0x91, 0x17, 0xc7, 0x31, 0xd6, 0xf8, 0xf4, 0x01, 0xb5, 0x38, 0x30, 0xd1,
- 0xfb, 0x39, 0x98, 0x5e, 0x36, 0x23, 0x5a, 0x89, 0x41, 0xa5, 0x35, 0x9a, 0xe3, 0xdb, 0xe0, 0x59,
- 0x00, 0xc7, 0x33, 0x0d, 0xa7, 0xe5, 0xb9, 0xce, 0x3e, 0x0f, 0xca, 0x2b, 0x14, 0x72, 0xdf, 0x75,
- 0xf6, 0x93, 0x1d, 0xe7, 0x2e, 0xcc, 0xae, 0x62, 0x23, 0x25, 0xed, 0x71, 0xb6, 0xd2, 0x6f, 0x4e,
- 0xf2, 0xc9, 0xca, 0x6f, 0xb6, 0x22, 0x23, 0xea, 0x86, 0x47, 0xe1, 0xf8, 0xfd, 0xa2, 0x18, 0x95,
- 0x4f, 0xc0, 0x84, 0x54, 0x4b, 0x70, 0x25, 0x7f, 0x50, 0x64, 0x91, 0x8b, 0xb4, 0xb0, 0x80, 0x12,
- 0x66, 0x5f, 0xd6, 0x37, 0x7e, 0xa4, 0xc0, 0x34, 0x39, 0xb5, 0xaf, 0x78, 0xae, 0x8b, 0xcd, 0x08,
- 0x5b, 0xf2, 0xc9, 0x5e, 0xc9, 0x3d, 0xd9, 0x8f, 0x91, 0x67, 0x68, 0x02, 0x44, 0x81, 0xe1, 0x86,
- 0xbe, 0x17, 0x44, 0xac, 0x78, 0x63, 0x66, 0xe9, 0xda, 0xa8, 0xea, 0x0b, 0x42, 0x5d, 0xe2, 0x81,
- 0x4e, 0xc0, 0x54, 0xc7, 0xb0, 0xac, 0x80, 0xd5, 0x70, 0x54, 0x74, 0xde, 0x6a, 0xbc, 0x0a, 0x2a,
- 0x51, 0x53, 0xc7, 0x26, 0xeb, 0x8c, 0xed, 0xb6, 0x47, 0xea, 0x8d, 0x20, 0x24, 0x51, 0xd4, 0x58,
- 0x66, 0xd0, 0xb6, 0x60, 0x82, 0xd6, 0x6b, 0xcc, 0x42, 0x95, 0xfc, 0x9b, 0x1c, 0x4d, 0xeb, 0x30,
- 0x4f, 0x00, 0xbd, 0x5c, 0x55, 0x05, 0x1d, 0x87, 0x39, 0xf1, 0x25, 0xb6, 0xb9, 0x5a, 0x90, 0x09,
- 0x64, 0xfd, 0xd5, 0xa2, 0xb6, 0x06, 0x95, 0xd8, 0x0c, 0x68, 0x06, 0xe0, 0x81, 0x1f, 0x25, 0x72,
- 0x00, 0xa6, 0x1e, 0xf8, 0xd1, 0x9d, 0xe5, 0x7b, 0xaa, 0xc2, 0x7f, 0xbf, 0xbd, 0x7c, 0x4f, 0x2d,
- 0x20, 0x15, 0x6a, 0x0f, 0xfc, 0xa8, 0x19, 0x78, 0x8f, 0xec, 0x8e, 0x1d, 0xed, 0xab, 0x45, 0xed,
- 0xef, 0x15, 0xe2, 0xe2, 0x5b, 0xdd, 0x36, 0x59, 0x3f, 0xa9, 0xa5, 0x43, 0x39, 0x8a, 0xfe, 0x33,
- 0x65, 0xcc, 0x30, 0x1a, 0xdd, 0x49, 0xd5, 0x20, 0x15, 0x46, 0xa9, 0x41, 0x62, 0xcb, 0x4f, 0x66,
- 0x49, 0x52, 0x7a, 0xb1, 0x2a, 0x0e, 0xc9, 0xa4, 0xfe, 0x5e, 0x11, 0x4e, 0xd0, 0xce, 0xac, 0xbb,
- 0xa1, 0x8f, 0x4d, 0xd6, 0x9f, 0x8d, 0xc8, 0x0b, 0x70, 0xe3, 0xeb, 0x47, 0xd8, 0x19, 0x36, 0xa1,
- 0xec, 0x78, 0x6d, 0xb9, 0x23, 0x2f, 0x66, 0x76, 0xa4, 0x4f, 0xe4, 0x1d, 0xaf, 0x4d, 0xfb, 0x45,
- 0xd9, 0xf2, 0x86, 0x5e, 0x72, 0xd8, 0x8f, 0xc6, 0x2f, 0x94, 0xe1, 0x31, 0x14, 0xba, 0x0a, 0x55,
- 0x5e, 0xf5, 0x60, 0x26, 0x65, 0x0f, 0x33, 0x87, 0x07, 0x0b, 0xc0, 0xca, 0x1e, 0x68, 0x39, 0x12,
- 0x2f, 0x8c, 0xa0, 0x75, 0x48, 0xf7, 0xa4, 0xaa, 0x28, 0xa9, 0xc6, 0xa8, 0x38, 0x52, 0x8d, 0x51,
- 0x5c, 0x1e, 0x15, 0x83, 0xd2, 0x53, 0x79, 0x62, 0x58, 0x2d, 0x84, 0x88, 0x19, 0xa7, 0xd2, 0xf7,
- 0xe6, 0x3e, 0x00, 0x35, 0xce, 0x91, 0x97, 0x4e, 0xf9, 0x14, 0xc7, 0xe7, 0x5d, 0x58, 0x57, 0xc8,
- 0xf4, 0x66, 0x04, 0x6c, 0xe2, 0x85, 0x7a, 0x89, 0xcd, 0xbc, 0x50, 0xfb, 0xd3, 0x02, 0xcc, 0x2f,
- 0x77, 0xa3, 0x9d, 0xb5, 0x47, 0xe6, 0x8e, 0xe1, 0xb6, 0xb1, 0x8e, 0x43, 0xdf, 0x73, 0x43, 0x8c,
- 0x9e, 0x83, 0x9a, 0x61, 0x9a, 0x38, 0x0c, 0x79, 0x4a, 0x8b, 0xd5, 0xed, 0x54, 0x19, 0x8c, 0x25,
- 0xa9, 0xe6, 0x61, 0x32, 0x34, 0x3d, 0x3f, 0xae, 0xdf, 0xa1, 0x0d, 0xba, 0x40, 0x06, 0x81, 0x27,
- 0x52, 0xc1, 0xac, 0x81, 0xae, 0xc0, 0x1c, 0xfd, 0xd1, 0xb2, 0x70, 0x68, 0x06, 0xb6, 0x4f, 0x4e,
- 0x20, 0x2c, 0xe5, 0xa9, 0xab, 0xf4, 0xc3, 0x6a, 0x02, 0x47, 0x1b, 0x50, 0xe6, 0x19, 0x76, 0x96,
- 0xef, 0xac, 0x2e, 0xbd, 0x9a, 0x39, 0x20, 0x59, 0x8a, 0x8b, 0x1c, 0x5e, 0xc8, 0x0b, 0x92, 0x04,
- 0xa3, 0xc6, 0x75, 0x98, 0x4e, 0x7d, 0x1a, 0xab, 0x20, 0xe9, 0x87, 0x0a, 0xd4, 0xe9, 0xc8, 0x10,
- 0x91, 0x9c, 0xcd, 0x06, 0x8e, 0xa8, 0x1d, 0x1a, 0xdf, 0x54, 0xe4, 0x34, 0xcc, 0x64, 0x62, 0xaf,
- 0xea, 0xd2, 0xa5, 0x91, 0xf5, 0xd6, 0x19, 0xdd, 0x93, 0x49, 0xce, 0x27, 0x5b, 0xe8, 0xff, 0x07,
- 0xb5, 0x37, 0xe5, 0x83, 0x4e, 0x40, 0x21, 0x76, 0x23, 0x5a, 0x39, 0xd4, 0xbc, 0xad, 0x17, 0xfc,
- 0x23, 0xde, 0xdf, 0xa2, 0x86, 0x74, 0xbc, 0x60, 0xc1, 0x76, 0xdc, 0xd6, 0x1c, 0x78, 0x46, 0xbe,
- 0x13, 0xd9, 0xe8, 0xfa, 0x2c, 0x87, 0xcf, 0x81, 0xc4, 0xc9, 0xe2, 0x2b, 0x18, 0xb1, 0x2b, 0x57,
- 0xf4, 0xaa, 0xb8, 0x5e, 0x61, 0xf3, 0x4a, 0x15, 0x28, 0xd8, 0xb5, 0x7c, 0xcf, 0xe6, 0x5b, 0x6f,
- 0x45, 0x9f, 0xe5, 0xf0, 0x35, 0x0e, 0xd6, 0xfe, 0x55, 0x81, 0x9a, 0x2c, 0x8e, 0x8c, 0xa7, 0xec,
- 0xbc, 0x4f, 0xd2, 0xc2, 0xe8, 0xb3, 0x80, 0x42, 0xd1, 0x9d, 0x56, 0xec, 0xad, 0xc5, 0x01, 0x85,
- 0x73, 0x83, 0x2c, 0xa1, 0xcf, 0x85, 0x3d, 0x90, 0x10, 0x9d, 0x06, 0xc0, 0x8f, 0x7c, 0x9b, 0xa5,
- 0xa0, 0xe9, 0x5c, 0x29, 0xea, 0x12, 0x44, 0xfb, 0x6d, 0x05, 0x4e, 0x4a, 0xee, 0xb8, 0xe2, 0x75,
- 0x7c, 0x07, 0x47, 0xf8, 0xa6, 0xe3, 0x3d, 0x6c, 0xbc, 0x9e, 0x78, 0xe4, 0x12, 0xd4, 0x4c, 0xc3,
- 0x71, 0xb6, 0x0c, 0x73, 0x97, 0x76, 0x94, 0x6d, 0xc3, 0xb3, 0x87, 0x07, 0x0b, 0xd5, 0x15, 0x0e,
- 0x27, 0x5d, 0xac, 0x0a, 0x24, 0xe2, 0x3e, 0xf2, 0x32, 0x12, 0x5f, 0x49, 0x29, 0x03, 0xae, 0xa4,
- 0x7e, 0xa8, 0xc0, 0x31, 0x49, 0x97, 0x75, 0xd7, 0x8e, 0xa8, 0x1e, 0x77, 0x53, 0x4b, 0x18, 0xb1,
- 0xa2, 0xa4, 0x03, 0x2b, 0xd3, 0xea, 0x46, 0x3b, 0x44, 0x7e, 0x89, 0x7c, 0x24, 0x86, 0x6d, 0x48,
- 0x93, 0xbf, 0x48, 0x03, 0x93, 0x64, 0x0e, 0x37, 0xa5, 0x9d, 0x20, 0xe1, 0x43, 0x77, 0x02, 0xc2,
- 0x83, 0xc0, 0xc8, 0x16, 0x18, 0x62, 0xb3, 0x1b, 0xe0, 0x78, 0x58, 0xcb, 0x6c, 0x0b, 0xdc, 0xa0,
- 0x50, 0x82, 0x57, 0x61, 0x08, 0x9b, 0x81, 0xa3, 0xfd, 0x42, 0x81, 0x73, 0x2b, 0x01, 0xb6, 0xc8,
- 0xe0, 0x1a, 0xce, 0xa7, 0x70, 0x60, 0x6f, 0x4b, 0xf7, 0x56, 0x72, 0x57, 0xa4, 0x5c, 0xeb, 0x55,
- 0x10, 0x2e, 0x2a, 0xf5, 0x86, 0x6e, 0x36, 0x9c, 0x88, 0x08, 0x01, 0x8e, 0x42, 0xfa, 0x94, 0x2e,
- 0xde, 0x2d, 0xf4, 0x16, 0xef, 0x22, 0x98, 0x70, 0x6c, 0x77, 0x97, 0xaf, 0x98, 0xf4, 0xf7, 0x87,
- 0xd0, 0xd5, 0xef, 0x28, 0x70, 0x69, 0x60, 0x57, 0x47, 0xf3, 0x20, 0x3b, 0xdb, 0x83, 0xd6, 0x65,
- 0x0f, 0xb2, 0x1b, 0x17, 0x84, 0xfa, 0xa7, 0x01, 0x6c, 0x2a, 0x72, 0xdb, 0xe6, 0x05, 0xab, 0x15,
- 0x5d, 0x82, 0x68, 0x5f, 0x2e, 0xc0, 0x49, 0xa6, 0x0b, 0xb6, 0x12, 0xed, 0x42, 0x7a, 0x3c, 0xfd,
- 0x8a, 0xb4, 0xb0, 0x5e, 0x81, 0xb9, 0x6d, 0xdb, 0x89, 0xe8, 0x96, 0xd6, 0xc3, 0x4e, 0x65, 0x1f,
- 0xd6, 0x63, 0x38, 0x39, 0x19, 0x0a, 0xe4, 0x30, 0xec, 0xf2, 0x72, 0xb1, 0x8a, 0x5e, 0xe3, 0x88,
- 0x14, 0x86, 0x2e, 0xc0, 0x2c, 0x7e, 0x64, 0x3a, 0x5d, 0x0b, 0xb7, 0xe8, 0xac, 0xe2, 0x65, 0x0a,
- 0x65, 0x7d, 0x86, 0x83, 0xd7, 0x18, 0xb4, 0x61, 0x88, 0xbe, 0x7c, 0x1a, 0xc0, 0x8c, 0x55, 0xe4,
- 0x2b, 0xfc, 0x47, 0xb3, 0x57, 0x78, 0x76, 0xcd, 0xd7, 0xdf, 0x31, 0x1d, 0xb7, 0xed, 0x30, 0xc2,
- 0x01, 0xb6, 0x74, 0x89, 0x97, 0xf6, 0x0d, 0x25, 0xbe, 0x1e, 0x65, 0x9b, 0x2b, 0xed, 0xbf, 0x14,
- 0x58, 0x3a, 0x63, 0xce, 0x48, 0x74, 0x1d, 0x4a, 0xdc, 0x01, 0x47, 0xbf, 0xd7, 0x16, 0x14, 0xda,
- 0x6f, 0xf5, 0x68, 0xb3, 0xe2, 0x59, 0x38, 0x35, 0x31, 0x95, 0xf4, 0xc4, 0x44, 0xe7, 0x60, 0xc6,
- 0xf4, 0x2c, 0xdc, 0x32, 0x77, 0x0c, 0xc7, 0xc1, 0x6e, 0x5b, 0x6c, 0xa1, 0xd3, 0x04, 0xba, 0x22,
- 0x80, 0x29, 0xe5, 0x8b, 0x03, 0x96, 0x93, 0xf7, 0x15, 0x58, 0xd0, 0xd3, 0x57, 0xc8, 0xf4, 0xba,
- 0x8c, 0xd9, 0x8e, 0x45, 0x47, 0xef, 0xa4, 0x96, 0x96, 0x91, 0x6c, 0x32, 0x62, 0x75, 0x50, 0xb2,
- 0x7b, 0x7e, 0x51, 0x81, 0x33, 0x59, 0x7a, 0x30, 0x08, 0x3f, 0xe1, 0x3e, 0x56, 0xc2, 0x7b, 0x41,
- 0x8c, 0xeb, 0x09, 0x28, 0x78, 0x6c, 0x53, 0x2e, 0xb3, 0x4d, 0xf9, 0xfe, 0x6d, 0xbd, 0xe0, 0xed,
- 0x6a, 0x3f, 0x04, 0x80, 0x8d, 0xfd, 0x30, 0xc2, 0x1d, 0x9a, 0xc0, 0x90, 0x5c, 0xe2, 0xdf, 0xe3,
- 0xb8, 0x78, 0x19, 0x4a, 0x7e, 0xe0, 0x91, 0xc0, 0x8c, 0x0b, 0xbe, 0x90, 0x3d, 0xd6, 0x31, 0x9b,
- 0xc5, 0x26, 0x43, 0xd7, 0x05, 0x1d, 0x7a, 0x03, 0x8a, 0xfe, 0x92, 0x3f, 0x30, 0xd9, 0x26, 0x93,
- 0x2f, 0x35, 0xd9, 0x52, 0xd4, 0x5c, 0x6a, 0xea, 0x84, 0x10, 0xdd, 0x83, 0x92, 0x17, 0x6c, 0xd9,
- 0x91, 0xb5, 0xc5, 0x0b, 0xaa, 0x86, 0xaa, 0x70, 0x9f, 0xa0, 0xaf, 0xde, 0x60, 0x43, 0xc0, 0x1b,
- 0xba, 0x60, 0x42, 0xb6, 0xee, 0x87, 0x46, 0xe0, 0x8a, 0xb3, 0x29, 0x6b, 0x34, 0xfe, 0x4d, 0x01,
- 0x81, 0x8a, 0xac, 0xe4, 0xe2, 0x3d, 0x8e, 0x3f, 0x58, 0xef, 0x5f, 0x1b, 0x51, 0xf4, 0xa2, 0x3c,
- 0xb4, 0xf4, 0xa4, 0xac, 0xcf, 0x72, 0x96, 0xf1, 0x95, 0xd7, 0x17, 0x60, 0xae, 0x0f, 0x8b, 0xcc,
- 0x04, 0x3f, 0xf0, 0xda, 0x81, 0x30, 0x78, 0x51, 0x8f, 0xdb, 0x34, 0xf5, 0x68, 0x3c, 0xb2, 0x3b,
- 0xdd, 0x0e, 0x35, 0x66, 0x51, 0x17, 0x4d, 0x42, 0xb5, 0xd5, 0xdd, 0xde, 0xc6, 0x62, 0xa1, 0x29,
- 0xea, 0x71, 0x9b, 0x9c, 0xc5, 0x59, 0xb1, 0x1b, 0xdf, 0xe7, 0x79, 0xab, 0xb1, 0x08, 0xc4, 0xc4,
- 0x64, 0xa9, 0x8a, 0x0f, 0xbf, 0x2d, 0x12, 0xba, 0x0b, 0xb9, 0x33, 0x31, 0x98, 0x44, 0xf6, 0x61,
- 0xe3, 0xeb, 0x53, 0x50, 0xe2, 0x63, 0x4b, 0x34, 0xd9, 0xc3, 0x41, 0x48, 0x82, 0x07, 0xb6, 0x4e,
- 0x8a, 0x26, 0x3a, 0x09, 0xa5, 0x3d, 0x33, 0x6c, 0x05, 0x78, 0x9b, 0x4f, 0xd3, 0xa9, 0x3d, 0x33,
- 0xd4, 0xf1, 0x36, 0x39, 0xc4, 0x74, 0xfd, 0xc8, 0xee, 0xe0, 0x56, 0x27, 0x64, 0x3a, 0xb2, 0x43,
- 0xcc, 0x26, 0x05, 0xde, 0xdd, 0xd0, 0xcb, 0xec, 0xf3, 0xdd, 0x10, 0x7d, 0x0c, 0xd4, 0x6e, 0x88,
- 0x83, 0x96, 0xe9, 0x77, 0x5b, 0x82, 0x02, 0x28, 0xc5, 0xdc, 0xe1, 0xc1, 0xc2, 0xf4, 0x66, 0x88,
- 0x83, 0x95, 0xe6, 0xe6, 0x03, 0x46, 0x36, 0x4d, 0x50, 0x57, 0xfc, 0xee, 0x03, 0x46, 0xfb, 0x49,
- 0x40, 0x21, 0x1d, 0x8d, 0x14, 0x75, 0x95, 0x52, 0xd3, 0xf2, 0x59, 0x36, 0x56, 0x09, 0xfd, 0x2c,
- 0x43, 0x4f, 0x38, 0x3c, 0x0b, 0x10, 0x46, 0x06, 0x8d, 0xbd, 0x8c, 0xa8, 0x5e, 0xa3, 0xb6, 0xa8,
- 0x70, 0xc8, 0x32, 0x7d, 0x2c, 0x13, 0x38, 0xe4, 0xc8, 0xde, 0x32, 0xbb, 0x41, 0x7d, 0x9a, 0x96,
- 0x4c, 0x57, 0x18, 0x64, 0xa5, 0x4b, 0xb7, 0x07, 0xb7, 0xdb, 0x69, 0xb5, 0xbd, 0xc0, 0xeb, 0x46,
- 0xb6, 0x8b, 0xeb, 0x33, 0x94, 0x41, 0xcd, 0xed, 0x76, 0x6e, 0x09, 0x18, 0x19, 0x12, 0xd7, 0xdb,
- 0xb6, 0x1d, 0x5c, 0x9f, 0x65, 0x43, 0xc2, 0x5a, 0xe8, 0x45, 0x38, 0x16, 0x79, 0x5e, 0xab, 0x63,
- 0xb8, 0xfb, 0x2d, 0xcf, 0xc7, 0x6e, 0x8b, 0x40, 0xc3, 0xba, 0x4a, 0xb7, 0x0e, 0x35, 0xf2, 0xbc,
- 0xbb, 0x86, 0xbb, 0x7f, 0xdf, 0xc7, 0xee, 0x4d, 0x02, 0x47, 0x67, 0xa1, 0x44, 0x64, 0x99, 0x7e,
- 0xb7, 0x3e, 0x47, 0x3b, 0x48, 0x13, 0x20, 0xf7, 0xba, 0xa4, 0x77, 0xfa, 0x94, 0xdb, 0x25, 0x9d,
- 0x22, 0xfa, 0xb6, 0xbd, 0x96, 0x18, 0x2d, 0x44, 0xc7, 0xa4, 0xd2, 0xf6, 0x3e, 0xc5, 0xc7, 0xeb,
- 0x12, 0xa8, 0x9e, 0x8f, 0x03, 0x5a, 0xe8, 0xd3, 0x62, 0xa6, 0xa8, 0x1f, 0x63, 0x31, 0x70, 0x0c,
- 0x67, 0x26, 0x43, 0x4f, 0x43, 0x65, 0xc7, 0x0b, 0xa3, 0x96, 0x6b, 0x74, 0x70, 0x7d, 0x9e, 0xe2,
- 0x94, 0x09, 0xe0, 0x9e, 0xd1, 0xc1, 0x24, 0xce, 0x30, 0x02, 0x73, 0xa7, 0x7e, 0x9c, 0xc5, 0x19,
- 0xe4, 0xb7, 0x64, 0xaa, 0x8e, 0xf1, 0xa8, 0x7e, 0x42, 0x36, 0xd5, 0x5d, 0xe3, 0x11, 0x89, 0x3e,
- 0x7c, 0xdb, 0xaa, 0x9f, 0xa4, 0xaa, 0xb3, 0x29, 0x4f, 0x8e, 0xdc, 0xbe, 0x6d, 0xa1, 0x67, 0x60,
- 0xc2, 0x27, 0xdf, 0xea, 0xf4, 0x5b, 0xf9, 0xf0, 0x60, 0x61, 0xa2, 0x49, 0x3e, 0x52, 0x28, 0x9b,
- 0x23, 0xb6, 0x17, 0xd8, 0xd1, 0x7e, 0xfd, 0x94, 0x98, 0x23, 0xac, 0x4d, 0x43, 0x1a, 0xdb, 0xaa,
- 0x37, 0x12, 0xa6, 0x9b, 0x84, 0x69, 0xd7, 0xb6, 0xd0, 0x02, 0x54, 0x1f, 0x7a, 0xc1, 0x2e, 0xe9,
- 0xa8, 0x65, 0x07, 0xf5, 0xa7, 0x59, 0xbc, 0xc0, 0x41, 0xab, 0x36, 0xdd, 0xb5, 0xb9, 0xef, 0x10,
- 0x9f, 0xa2, 0xdd, 0x7c, 0x86, 0x22, 0xcd, 0x30, 0xf0, 0x26, 0x87, 0x6a, 0xbf, 0x9e, 0x84, 0x32,
- 0x99, 0x14, 0xbd, 0x3b, 0xe9, 0xb2, 0x58, 0x35, 0x3f, 0x0a, 0x93, 0x62, 0x2a, 0x15, 0x73, 0x2f,
- 0x45, 0x04, 0x07, 0xfa, 0x43, 0x67, 0x04, 0x8d, 0x0f, 0x0a, 0x30, 0x41, 0xda, 0xd2, 0x1b, 0x8c,
- 0x4a, 0xea, 0x0d, 0xc6, 0x75, 0x98, 0x22, 0x6e, 0x84, 0x59, 0x22, 0x22, 0x6f, 0x41, 0x8d, 0x79,
- 0xeb, 0x04, 0x57, 0xe7, 0x24, 0xc4, 0xf1, 0xe8, 0x89, 0x58, 0x84, 0xbf, 0xbc, 0x85, 0x96, 0xa1,
- 0xbc, 0x8d, 0x8d, 0xa8, 0x1b, 0x60, 0xb6, 0x2a, 0xce, 0xe4, 0x3d, 0x5f, 0x11, 0x6c, 0x6f, 0x32,
- 0x6c, 0x3d, 0x26, 0x23, 0xd6, 0xed, 0xd8, 0x6e, 0xcb, 0x31, 0x22, 0xec, 0x9a, 0xec, 0xfd, 0x55,
- 0x51, 0x87, 0x8e, 0xed, 0xde, 0x61, 0x10, 0xe2, 0x3e, 0x76, 0xd8, 0xa2, 0x19, 0x5c, 0xcc, 0xd3,
- 0xe9, 0x65, 0x3b, 0xa4, 0xf9, 0x63, 0x8c, 0x3e, 0x0e, 0x15, 0xcb, 0x0e, 0xb0, 0x49, 0xcf, 0x23,
- 0xa5, 0x01, 0x89, 0x92, 0x55, 0x81, 0xa5, 0x27, 0x04, 0x8d, 0x9f, 0x91, 0xed, 0x8a, 0xf4, 0x30,
- 0x2d, 0x44, 0xe9, 0x11, 0x52, 0x87, 0x92, 0x61, 0x59, 0x74, 0x69, 0x65, 0x6b, 0x93, 0x68, 0xa6,
- 0xc5, 0x17, 0xc7, 0x14, 0x4f, 0xf8, 0x8a, 0x6e, 0xb3, 0x25, 0x56, 0x34, 0xd1, 0x1b, 0x50, 0x0a,
- 0xa3, 0x00, 0x1b, 0x1d, 0x91, 0x6c, 0x78, 0x7e, 0xb0, 0x59, 0x37, 0x28, 0xb2, 0x2e, 0x88, 0x1a,
- 0x67, 0x60, 0x8a, 0x81, 0xf2, 0xdc, 0x41, 0x7b, 0x0f, 0x4a, 0x7c, 0x2c, 0x10, 0x82, 0x19, 0x9e,
- 0x76, 0xe4, 0x10, 0xf5, 0x29, 0x34, 0x0b, 0xd5, 0xb7, 0x71, 0xb8, 0x23, 0x00, 0x0a, 0x9a, 0x01,
- 0xb8, 0x71, 0x67, 0x4d, 0xb4, 0x69, 0x1a, 0xf2, 0x8e, 0x67, 0x1a, 0x8e, 0x80, 0x14, 0x69, 0x02,
- 0xd3, 0x0b, 0x44, 0x7b, 0x82, 0xb0, 0x78, 0xab, 0x6b, 0x9b, 0x02, 0x30, 0xa9, 0x7d, 0x5f, 0x81,
- 0x72, 0x53, 0xec, 0x49, 0xf3, 0x30, 0x19, 0x46, 0x46, 0x24, 0xce, 0xd7, 0xac, 0x41, 0xa0, 0x96,
- 0x67, 0xbb, 0x6d, 0x91, 0xed, 0xa0, 0x8d, 0xd4, 0xde, 0x46, 0x8c, 0x5c, 0x90, 0xf6, 0xb6, 0x67,
- 0xa0, 0x62, 0xf2, 0x33, 0x02, 0xdb, 0xa8, 0x26, 0xf4, 0x04, 0xc0, 0x4e, 0xdb, 0x91, 0xe1, 0x50,
- 0xb7, 0x9a, 0xd0, 0x59, 0x83, 0x4a, 0xc1, 0x8e, 0xc1, 0x9e, 0x41, 0x4e, 0xe8, 0xac, 0xa1, 0xb9,
- 0x30, 0xc7, 0x6e, 0x35, 0xde, 0xb6, 0xa3, 0x1d, 0x96, 0x22, 0x0b, 0xc7, 0x79, 0x87, 0xb3, 0x08,
- 0x55, 0x96, 0x4e, 0x0b, 0x5b, 0xfe, 0x6e, 0xea, 0x95, 0x93, 0xc8, 0xb7, 0x85, 0x3a, 0x70, 0x8c,
- 0xe6, 0x6e, 0xa8, 0x1d, 0x28, 0x30, 0x77, 0xbf, 0x1b, 0xdd, 0xdf, 0xa6, 0xd9, 0x4d, 0xf1, 0x6e,
- 0x6c, 0x40, 0x3e, 0x71, 0x8c, 0xcc, 0xbc, 0xf4, 0x38, 0x87, 0x18, 0x6c, 0x2a, 0x79, 0x8f, 0xc7,
- 0x1f, 0xd9, 0x4d, 0x24, 0x8f, 0xec, 0xe6, 0x61, 0x72, 0xdb, 0x31, 0xda, 0x21, 0xb5, 0x51, 0x49,
- 0x67, 0x0d, 0x9a, 0x1c, 0x13, 0x6f, 0xda, 0x5a, 0xe9, 0xd4, 0xa0, 0x1a, 0x7f, 0x68, 0xf2, 0xa7,
- 0x8b, 0xf1, 0x23, 0xb1, 0x92, 0xf4, 0x48, 0x4c, 0xfb, 0x89, 0x02, 0xc7, 0x32, 0x2a, 0xcb, 0xd0,
- 0x2a, 0x00, 0x0b, 0x8d, 0xa5, 0x5b, 0x0f, 0x69, 0xd9, 0xe8, 0x86, 0x3b, 0x3d, 0x35, 0x69, 0x34,
- 0x68, 0x66, 0x69, 0xe5, 0x48, 0xfc, 0x24, 0xd6, 0xd8, 0xea, 0xba, 0x96, 0x83, 0x93, 0xd2, 0x54,
- 0x6a, 0x8d, 0x1b, 0x14, 0xb8, 0xbe, 0x4a, 0x22, 0x19, 0xfa, 0xcb, 0x4a, 0x72, 0x2e, 0xfc, 0xb6,
- 0x98, 0xe5, 0x5c, 0xae, 0xc1, 0x7c, 0x80, 0x4d, 0xdb, 0xb7, 0xb1, 0x1b, 0xb5, 0xa4, 0xa3, 0x30,
- 0x33, 0x0d, 0x8a, 0xbf, 0x35, 0xc5, 0x99, 0x58, 0xbb, 0x07, 0x90, 0x14, 0xb0, 0xb1, 0x87, 0xbc,
- 0xe4, 0x97, 0xfc, 0xfa, 0x95, 0x41, 0xc8, 0x01, 0x5a, 0xca, 0x23, 0x91, 0xd5, 0x82, 0x7b, 0xb4,
- 0x38, 0xa4, 0x2f, 0x5b, 0x56, 0xa0, 0x7d, 0x55, 0x81, 0x53, 0x84, 0x21, 0x1b, 0x40, 0x5e, 0xa2,
- 0x2b, 0xce, 0x62, 0xe8, 0x8d, 0x74, 0xda, 0x6e, 0xf4, 0xca, 0x3d, 0xde, 0xbf, 0xd1, 0xdd, 0x85,
- 0x9c, 0x29, 0x1a, 0x89, 0x22, 0xbc, 0x64, 0x2f, 0xd1, 0xe4, 0x55, 0x98, 0xe2, 0xd5, 0x7e, 0xca,
- 0x68, 0xd5, 0x7e, 0x1c, 0x7d, 0x1c, 0x15, 0x7e, 0x5c, 0x88, 0xdf, 0x7e, 0x0c, 0x3a, 0xa1, 0x8e,
- 0x53, 0x53, 0x7c, 0x1d, 0x1a, 0xa1, 0xdd, 0x76, 0xb1, 0xc5, 0x8f, 0xe7, 0xd1, 0x7e, 0xab, 0x2f,
- 0xe3, 0x71, 0x92, 0x61, 0xac, 0x73, 0x84, 0x78, 0xac, 0xd1, 0x55, 0x38, 0xb6, 0xc7, 0xf5, 0x68,
- 0x49, 0x07, 0x6c, 0x96, 0x0e, 0x41, 0x7b, 0x7d, 0x2a, 0x92, 0x09, 0x13, 0x50, 0x35, 0x59, 0x2a,
- 0xac, 0x65, 0x91, 0xc5, 0x8d, 0x2d, 0xeb, 0xaa, 0xfc, 0x61, 0x95, 0xac, 0x73, 0xf4, 0x9c, 0x2f,
- 0xb2, 0x66, 0x0c, 0x95, 0x6d, 0x7c, 0x33, 0x09, 0x98, 0x22, 0xa6, 0x53, 0x15, 0x53, 0xbd, 0xa9,
- 0x0a, 0xb2, 0x31, 0xf3, 0x74, 0x42, 0x89, 0x45, 0xcd, 0xac, 0xa5, 0x7d, 0x4b, 0x81, 0xe3, 0x64,
- 0x40, 0xd8, 0x3a, 0x45, 0x5d, 0x6b, 0xd3, 0x27, 0x72, 0x8e, 0x3e, 0x98, 0xf1, 0x2c, 0x2a, 0xc8,
- 0xb3, 0x68, 0x8c, 0x5b, 0xdf, 0xff, 0x50, 0xa0, 0x4a, 0xf8, 0x72, 0x47, 0x6d, 0x9c, 0x4d, 0x0e,
- 0xa9, 0xd2, 0xf5, 0x83, 0x92, 0xba, 0x7e, 0x68, 0xfc, 0x4d, 0x7c, 0xa2, 0xfc, 0x64, 0x52, 0x40,
- 0xc1, 0x34, 0x3f, 0x9f, 0xa9, 0x79, 0xdf, 0x92, 0x9a, 0xbc, 0x65, 0x25, 0x7b, 0x85, 0x83, 0x49,
- 0x40, 0xfe, 0x48, 0xdc, 0x95, 0x26, 0x00, 0x74, 0x11, 0x54, 0x7e, 0x12, 0x4f, 0x9c, 0x84, 0x2d,
- 0x18, 0x33, 0xec, 0x10, 0x1e, 0xfb, 0xc6, 0x25, 0x50, 0x0d, 0x27, 0xc0, 0x86, 0xb5, 0xdf, 0x0a,
- 0xf8, 0x0b, 0x16, 0x3a, 0xd2, 0x65, 0x7d, 0x96, 0xc3, 0xc5, 0xc3, 0x16, 0xed, 0x37, 0x64, 0xcf,
- 0xa3, 0xb6, 0x74, 0xad, 0xc6, 0xf7, 0xa4, 0xdc, 0xd1, 0x80, 0x75, 0x3e, 0x4b, 0x91, 0x42, 0xa6,
- 0x22, 0xb7, 0x61, 0x9a, 0x61, 0xb2, 0x4d, 0x48, 0xe4, 0x7a, 0xcf, 0xe7, 0x14, 0xa6, 0xf4, 0x6c,
- 0x6e, 0x7a, 0xad, 0xcd, 0x8a, 0x2f, 0x28, 0x6d, 0xe3, 0x81, 0x30, 0x74, 0x1f, 0x57, 0xe5, 0xe8,
- 0x5c, 0xb5, 0x1f, 0x2b, 0x30, 0x43, 0x0d, 0xb0, 0x63, 0x04, 0x6c, 0x89, 0x6b, 0xfc, 0xe5, 0x11,
- 0xee, 0xf1, 0x12, 0xaf, 0x2d, 0x8c, 0xe7, 0xb5, 0xab, 0x50, 0xe6, 0x63, 0x14, 0xf0, 0x2c, 0xc0,
- 0xe8, 0x0b, 0x69, 0x4c, 0x99, 0x64, 0x5f, 0x5c, 0x40, 0x0c, 0x33, 0x92, 0x16, 0xed, 0xc6, 0xfd,
- 0xa4, 0x43, 0xb2, 0x3c, 0xe5, 0xf1, 0xe5, 0xbd, 0x0b, 0xd3, 0x5c, 0x1e, 0xeb, 0x57, 0xe3, 0x46,
- 0x22, 0xea, 0xa8, 0x33, 0x39, 0xe1, 0xfe, 0x3a, 0xcc, 0xdd, 0xb4, 0x83, 0x30, 0xba, 0x63, 0x84,
- 0xd1, 0x0a, 0x0b, 0x10, 0x68, 0x64, 0xb6, 0x4d, 0x80, 0xfc, 0x25, 0x3f, 0x6b, 0xd0, 0x7c, 0xb0,
- 0x11, 0x46, 0xfc, 0xad, 0x2f, 0xfd, 0xad, 0xfd, 0x93, 0x02, 0xc7, 0x78, 0xde, 0x42, 0xaa, 0x7a,
- 0x62, 0x27, 0x61, 0x6c, 0x38, 0xd8, 0x6a, 0x6d, 0x79, 0x8f, 0xc4, 0x44, 0x63, 0x90, 0x1b, 0xde,
- 0x23, 0xb2, 0x33, 0x06, 0xc6, 0xc3, 0x56, 0xe0, 0xb1, 0xa2, 0x3f, 0x3e, 0xc9, 0xaa, 0x81, 0xf1,
- 0x50, 0xe7, 0xa0, 0xc6, 0xfb, 0x0a, 0x14, 0x09, 0xaa, 0x14, 0x79, 0x2b, 0xe9, 0xc8, 0x7b, 0x1e,
- 0x26, 0xe9, 0x5f, 0x7c, 0x10, 0xab, 0x11, 0x6d, 0x8c, 0xb1, 0x1a, 0xf5, 0x3e, 0x73, 0xa8, 0x65,
- 0x56, 0x01, 0xfc, 0x5a, 0x81, 0xe3, 0x3a, 0xde, 0x0e, 0x70, 0xb8, 0x93, 0x2e, 0x01, 0x6e, 0xbc,
- 0x32, 0xe4, 0xb8, 0x35, 0x0f, 0x93, 0xac, 0x90, 0xa1, 0xc0, 0x92, 0x45, 0xac, 0x8e, 0xe1, 0xad,
- 0x23, 0xd6, 0xe2, 0x12, 0x43, 0x44, 0x76, 0x07, 0x7b, 0xdd, 0x48, 0xa4, 0x70, 0x78, 0xb3, 0xf1,
- 0x8e, 0x98, 0xb6, 0x4d, 0xa8, 0xd2, 0xa3, 0x60, 0x6b, 0xdb, 0xeb, 0xba, 0x16, 0x9f, 0xb4, 0x57,
- 0x33, 0x7d, 0x22, 0xb3, 0x4b, 0xec, 0x38, 0x09, 0x94, 0xc7, 0x4d, 0xc2, 0xe2, 0xb2, 0x0d, 0xc9,
- 0x8d, 0x3e, 0x3a, 0xc1, 0x0b, 0x02, 0x59, 0x35, 0x84, 0x85, 0xb7, 0x6d, 0x17, 0x5b, 0xea, 0x53,
- 0x68, 0x9e, 0xd7, 0x70, 0x11, 0x38, 0xdf, 0xc0, 0x55, 0x25, 0x05, 0xe5, 0x62, 0x58, 0x29, 0x44,
- 0x0c, 0x95, 0xaa, 0x40, 0xd5, 0xe2, 0xe5, 0x2f, 0x55, 0xa0, 0x92, 0x5c, 0x5c, 0x9f, 0x00, 0x14,
- 0x37, 0x64, 0x59, 0x67, 0x61, 0x21, 0x86, 0xdf, 0x4a, 0x56, 0x19, 0x36, 0xba, 0xf4, 0xb1, 0x95,
- 0xaa, 0xf4, 0x23, 0xc9, 0x6f, 0xd0, 0x19, 0x52, 0x01, 0x2d, 0xc0, 0xd3, 0x31, 0x52, 0xff, 0x23,
- 0x5f, 0x15, 0xa3, 0x67, 0xe1, 0x54, 0x26, 0xc2, 0x1d, 0xbc, 0x1d, 0xa9, 0xdb, 0xe8, 0x32, 0x9c,
- 0xef, 0xfd, 0x9c, 0xfd, 0x94, 0x56, 0x6d, 0xa3, 0x4b, 0x70, 0x6e, 0x30, 0xae, 0x78, 0xea, 0xb0,
- 0x83, 0xae, 0xc1, 0x0b, 0x83, 0x51, 0xd3, 0x2f, 0x61, 0x55, 0x1b, 0x2d, 0xc1, 0xe2, 0x60, 0x8a,
- 0xfb, 0xdd, 0xa8, 0x4d, 0x4e, 0x51, 0xe2, 0xe9, 0xaa, 0xfa, 0x39, 0xb4, 0x08, 0x97, 0x47, 0xa3,
- 0xd9, 0xc0, 0x6e, 0xa4, 0xee, 0x0e, 0x97, 0xb1, 0xee, 0x9a, 0x5e, 0xc7, 0x76, 0xdb, 0x62, 0xdb,
- 0x53, 0x1d, 0xf4, 0x32, 0x5c, 0x1d, 0x8d, 0x26, 0x7e, 0x26, 0xa9, 0x76, 0x46, 0x17, 0x24, 0xde,
- 0x37, 0xaa, 0x2e, 0xd2, 0xe0, 0x74, 0x0e, 0x0d, 0x7f, 0x69, 0xa8, 0x7a, 0xe8, 0x79, 0x38, 0x93,
- 0x83, 0x13, 0xbf, 0x0d, 0x54, 0x7d, 0xa4, 0xc1, 0xb3, 0x31, 0x56, 0x4f, 0xbd, 0x3b, 0x73, 0x9b,
- 0x1f, 0x29, 0xe8, 0x1a, 0x5c, 0x89, 0x71, 0x06, 0xd6, 0x6d, 0x33, 0x8a, 0x1f, 0x14, 0xd0, 0x2b,
- 0x92, 0x21, 0xfa, 0x2b, 0x9f, 0xa5, 0x37, 0xf6, 0xcb, 0xae, 0xeb, 0x75, 0x5d, 0x13, 0x5b, 0xea,
- 0x9f, 0x17, 0xd0, 0x22, 0x5c, 0xca, 0x97, 0x93, 0xaa, 0xdc, 0xc6, 0x96, 0xfa, 0x17, 0x05, 0x74,
- 0x1e, 0x9e, 0xeb, 0xed, 0x61, 0xdf, 0x43, 0x44, 0xf5, 0x5b, 0x45, 0x74, 0x11, 0xce, 0x0e, 0xc2,
- 0xe3, 0x2f, 0x04, 0xd5, 0x6f, 0x17, 0xd1, 0x69, 0x69, 0x02, 0xf4, 0xbe, 0xec, 0x53, 0xbf, 0x53,
- 0x44, 0x67, 0x25, 0xbb, 0x67, 0x46, 0x9a, 0xea, 0x1f, 0x14, 0xd1, 0x05, 0xd0, 0x52, 0x48, 0x99,
- 0x27, 0x1d, 0xf5, 0xbb, 0x69, 0xbd, 0xf2, 0x4f, 0x22, 0xea, 0x1f, 0x16, 0xd1, 0x4b, 0xfd, 0x53,
- 0x64, 0xd0, 0x81, 0x41, 0xfd, 0x65, 0x31, 0x65, 0x9c, 0x54, 0xa1, 0x2d, 0x3f, 0xbf, 0x52, 0x37,
- 0xff, 0x97, 0xd2, 0xe5, 0x6f, 0x88, 0x8a, 0x8a, 0x8c, 0x42, 0x20, 0x74, 0x0e, 0x9e, 0xcb, 0xfb,
- 0xd6, 0xb3, 0x44, 0xe5, 0xa1, 0xf1, 0x3d, 0x52, 0x55, 0x88, 0x3f, 0xe6, 0x23, 0x31, 0xd5, 0xd4,
- 0xc2, 0xe5, 0xbf, 0x55, 0xe2, 0xd7, 0x21, 0xec, 0x89, 0xd4, 0xa9, 0xf8, 0x21, 0x0a, 0x6d, 0xcb,
- 0x62, 0x7b, 0x3e, 0x3d, 0xf0, 0xf8, 0x84, 0x51, 0x15, 0xb2, 0xe8, 0xca, 0x9f, 0xe2, 0x39, 0x5a,
- 0x40, 0xc7, 0x61, 0x4e, 0xfe, 0xc2, 0x9c, 0xa4, 0x88, 0x4e, 0xc6, 0xcf, 0x3d, 0x38, 0x01, 0xf3,
- 0x89, 0x89, 0x5e, 0x21, 0xc9, 0xcc, 0x9d, 0xec, 0xa5, 0x11, 0x53, 0x6f, 0xea, 0xf2, 0x2d, 0xa8,
- 0xc4, 0xb9, 0x2f, 0x34, 0x03, 0xc0, 0x33, 0x4d, 0xab, 0x76, 0xa0, 0x3e, 0x45, 0xda, 0xeb, 0xee,
- 0x16, 0xd9, 0x6b, 0x48, 0x5b, 0x41, 0xb3, 0x50, 0xbd, 0xdf, 0x8d, 0x62, 0x40, 0x01, 0x55, 0x60,
- 0xf2, 0x86, 0x4d, 0x7e, 0x16, 0x97, 0x3e, 0xb8, 0x02, 0xb3, 0xe2, 0xaf, 0xe0, 0x88, 0x5a, 0x8d,
- 0x30, 0xe3, 0x01, 0x27, 0x5a, 0x1c, 0x74, 0xa9, 0x98, 0xe0, 0x2d, 0xc6, 0xaf, 0x3c, 0x47, 0xc6,
- 0xf7, 0x9d, 0xfd, 0x6b, 0x0a, 0xfa, 0xb2, 0x92, 0xfb, 0xce, 0x13, 0xbd, 0x32, 0xd6, 0x13, 0x3e,
- 0xa1, 0xc1, 0xd2, 0x98, 0x54, 0x64, 0xb7, 0x27, 0x5a, 0xe4, 0x6c, 0x0d, 0x39, 0x5a, 0xe4, 0x60,
- 0x0f, 0xd1, 0x22, 0x9f, 0x8a, 0x68, 0xf1, 0x85, 0x9c, 0xc7, 0x6f, 0x68, 0x14, 0x66, 0x1c, 0x37,
- 0x56, 0xe0, 0xda, 0x58, 0x34, 0x44, 0xfc, 0xe7, 0xb3, 0x9f, 0xd3, 0xa1, 0x97, 0x46, 0xe0, 0xc4,
- 0x50, 0x63, 0xe1, 0x57, 0xc7, 0x21, 0x21, 0xb2, 0xbf, 0xad, 0x0c, 0x7e, 0x69, 0x87, 0x5e, 0x1b,
- 0xc9, 0x9e, 0x32, 0x49, 0xac, 0xcc, 0xab, 0x47, 0x21, 0x25, 0x4a, 0x45, 0x59, 0x4f, 0xf2, 0xd0,
- 0x28, 0x7d, 0x23, 0x88, 0xb1, 0xfc, 0x17, 0x47, 0x27, 0xc8, 0x1c, 0x06, 0xb6, 0x3d, 0x8f, 0x34,
- 0x0c, 0x0c, 0x75, 0xac, 0x61, 0x88, 0x49, 0xf2, 0x3c, 0x90, 0xac, 0x4a, 0xa3, 0x7a, 0x20, 0xc1,
- 0x1d, 0xd7, 0x03, 0x39, 0x0d, 0x11, 0xbf, 0x95, 0x7e, 0xc0, 0x87, 0x2e, 0x0d, 0xe2, 0x40, 0x51,
- 0x62, 0x61, 0x17, 0x46, 0x41, 0x25, 0x32, 0x76, 0x7a, 0x9f, 0xf4, 0xa1, 0x2b, 0x83, 0x48, 0x39,
- 0x52, 0x2c, 0xe7, 0xd2, 0x68, 0xc8, 0x44, 0xd2, 0xc3, 0xcc, 0x87, 0x7e, 0x68, 0xa0, 0x59, 0x64,
- 0xcc, 0x58, 0xe6, 0xe2, 0x18, 0x14, 0x44, 0xf0, 0x17, 0x95, 0xbc, 0xf7, 0x80, 0xe8, 0xe5, 0xec,
- 0xb4, 0x43, 0x26, 0x72, 0x2c, 0xff, 0xa5, 0xf1, 0x88, 0xb8, 0x13, 0x67, 0xbd, 0x1d, 0x44, 0xa3,
- 0xb1, 0x22, 0xa8, 0x43, 0x9c, 0x38, 0x87, 0x84, 0x3b, 0x71, 0xe6, 0xcb, 0xc2, 0x1c, 0x27, 0xce,
- 0xc4, 0x1d, 0xe2, 0xc4, 0x79, 0x34, 0x44, 0xfc, 0x0f, 0x94, 0x11, 0x1f, 0x21, 0xa2, 0x1b, 0x23,
- 0xf1, 0xce, 0xa4, 0x8d, 0xf5, 0xfb, 0xe4, 0x63, 0xf1, 0x20, 0xfa, 0xfe, 0xd1, 0xd0, 0xe7, 0x8c,
- 0xe8, 0xfa, 0x68, 0x42, 0x52, 0x44, 0xb1, 0x86, 0xaf, 0x1d, 0x8d, 0x98, 0xa8, 0xf6, 0xc7, 0x23,
- 0xbc, 0x6f, 0x44, 0xaf, 0x8f, 0xc4, 0xbf, 0x97, 0x2c, 0x56, 0xef, 0xfa, 0x51, 0xc9, 0x89, 0x82,
- 0xbb, 0x7d, 0x8f, 0x1d, 0x51, 0x76, 0x00, 0xd4, 0x83, 0x15, 0x4b, 0xbf, 0x3c, 0x22, 0x36, 0x5f,
- 0xb9, 0xd2, 0xcf, 0x19, 0x73, 0x56, 0xae, 0x34, 0xd2, 0x90, 0x95, 0xab, 0x0f, 0x99, 0x48, 0x72,
- 0x33, 0x9e, 0xd0, 0xe5, 0x44, 0x82, 0x7d, 0x78, 0x43, 0x56, 0xe4, 0xfe, 0x67, 0x90, 0xd7, 0x14,
- 0xb4, 0xdb, 0xff, 0x72, 0x0d, 0xbd, 0x38, 0x88, 0x3c, 0x46, 0x8b, 0xa5, 0x9d, 0x1f, 0x8a, 0x2e,
- 0x84, 0xbd, 0x23, 0x3d, 0x17, 0x43, 0x03, 0xc8, 0x68, 0x21, 0x91, 0x60, 0xff, 0xfc, 0x50, 0x3c,
- 0x62, 0x37, 0xdc, 0xf3, 0x12, 0x0b, 0xe5, 0x0c, 0xaf, 0x8c, 0x13, 0x8b, 0xb8, 0x38, 0x12, 0x2e,
- 0xf7, 0xba, 0x9e, 0x47, 0x58, 0x39, 0x5e, 0xd7, 0x83, 0x35, 0xc4, 0xeb, 0xfa, 0xb1, 0x89, 0xb0,
- 0x30, 0xe3, 0x85, 0xd6, 0x20, 0x5f, 0x48, 0xbd, 0x4b, 0x1a, 0x7c, 0x2a, 0xc8, 0xc2, 0x67, 0xa7,
- 0x82, 0x4e, 0xdf, 0x1b, 0x9c, 0xdc, 0x1e, 0xa6, 0xb0, 0x86, 0xf6, 0xb0, 0x17, 0x9b, 0x89, 0xfb,
- 0x92, 0x92, 0xf7, 0x4c, 0x26, 0x67, 0xc3, 0xcc, 0x46, 0x1e, 0xb2, 0x61, 0xe6, 0x12, 0x31, 0x25,
- 0xde, 0x95, 0x9f, 0x86, 0xa0, 0x0b, 0xf9, 0x2c, 0xd2, 0x63, 0x79, 0x6e, 0x38, 0x22, 0x19, 0xc6,
- 0xaf, 0x0e, 0x78, 0xdf, 0x80, 0xfe, 0x4f, 0x3e, 0x8f, 0x0c, 0xf4, 0x58, 0xf4, 0xcb, 0xe3, 0x92,
- 0x11, 0x45, 0xde, 0x95, 0xab, 0x1d, 0xd1, 0xd0, 0x22, 0xc2, 0xc1, 0xdd, 0x4c, 0x21, 0xf2, 0x98,
- 0x2b, 0xa3, 0x4a, 0x3d, 0x27, 0xe6, 0xca, 0xc0, 0x1c, 0x12, 0x73, 0x65, 0x53, 0x88, 0x13, 0x64,
- 0x4e, 0xad, 0x7e, 0xce, 0x09, 0x32, 0x07, 0x7b, 0xc8, 0x09, 0x32, 0x9f, 0x4a, 0xc4, 0x1e, 0x23,
- 0x15, 0xbb, 0xe7, 0xc4, 0x1e, 0x23, 0xd1, 0x0e, 0x89, 0x3d, 0x46, 0xe5, 0x41, 0xf4, 0xfd, 0xeb,
- 0x71, 0x2a, 0xd6, 0xd1, 0xcd, 0xf1, 0xe5, 0x65, 0x5a, 0x76, 0xf5, 0xb1, 0xf9, 0x10, 0xdd, 0xdf,
- 0x57, 0x72, 0xeb, 0xda, 0x73, 0x46, 0x3c, 0x07, 0x7b, 0xc8, 0x88, 0xe7, 0x53, 0xb1, 0x75, 0x23,
- 0xcc, 0x28, 0x2c, 0x1f, 0x9c, 0xb6, 0x49, 0xf0, 0x46, 0x4b, 0xdb, 0xa4, 0xf0, 0x99, 0xd0, 0xef,
- 0x0d, 0xaf, 0xdf, 0x46, 0x1f, 0xcf, 0xb9, 0x2d, 0x19, 0x48, 0x15, 0x6b, 0xf4, 0xb1, 0x23, 0x52,
- 0x93, 0xa1, 0xf9, 0x54, 0x52, 0x18, 0x88, 0x86, 0x94, 0xd0, 0x09, 0x71, 0xc3, 0x0a, 0xf8, 0x28,
- 0xdf, 0x56, 0xea, 0xca, 0x1d, 0xe5, 0xdf, 0x45, 0x72, 0x8c, 0x21, 0xd1, 0x49, 0x1a, 0x53, 0x28,
- 0xce, 0xef, 0xb7, 0xf3, 0x14, 0xe7, 0x9f, 0x87, 0x29, 0x9e, 0xa0, 0xf1, 0xd0, 0x31, 0x7d, 0x6d,
- 0x9c, 0x13, 0x3a, 0xa6, 0x91, 0x86, 0x84, 0x8e, 0x7d, 0xc8, 0x3c, 0x67, 0xd2, 0x7f, 0xa5, 0x9b,
- 0x93, 0x33, 0xe9, 0x47, 0x1c, 0x92, 0x33, 0xc9, 0x24, 0xe0, 0x81, 0x57, 0xea, 0x62, 0x37, 0x27,
- 0xf0, 0x4a, 0xe1, 0x0c, 0x09, 0xbc, 0x7a, 0x71, 0xf9, 0xc9, 0x32, 0xf3, 0xb2, 0x2f, 0xe7, 0x64,
- 0x99, 0x7d, 0x31, 0x38, 0xf8, 0x64, 0x99, 0x47, 0xe3, 0x3b, 0xfb, 0x37, 0x3e, 0xf2, 0xd3, 0x7f,
- 0x3e, 0xfd, 0xd4, 0xdf, 0x1d, 0x9e, 0x56, 0x7e, 0x7a, 0x78, 0x5a, 0xf9, 0xf9, 0xe1, 0x69, 0xe5,
- 0x33, 0xcf, 0x6f, 0xe1, 0x20, 0xda, 0x5f, 0x8c, 0xb0, 0xb9, 0x73, 0x95, 0x73, 0xbb, 0xea, 0xef,
- 0xb6, 0xaf, 0xa6, 0xfe, 0x07, 0x8a, 0xad, 0x29, 0xda, 0x7c, 0xf9, 0xbf, 0x03, 0x00, 0x00, 0xff,
- 0xff, 0xa9, 0x08, 0x9c, 0x77, 0x99, 0x62, 0x00, 0x00,
+ // 6383 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x7c, 0x4b, 0x6c, 0x1c, 0xc9,
+ 0x79, 0xf0, 0xf6, 0x0c, 0xc9, 0x99, 0xf9, 0x86, 0x8f, 0x66, 0x89, 0x92, 0x46, 0xb3, 0x92, 0xa8,
+ 0x6d, 0xad, 0x9e, 0xbb, 0x4b, 0x69, 0xb9, 0xfb, 0x7b, 0xbd, 0x96, 0x77, 0x6d, 0x8a, 0xa4, 0xf4,
+ 0x73, 0xf5, 0x9a, 0x6d, 0x8a, 0x5e, 0xaf, 0xb1, 0xc8, 0xb8, 0xd9, 0x5d, 0x1c, 0xb6, 0xd9, 0xd3,
+ 0xdd, 0xdb, 0x0f, 0x52, 0x34, 0xe2, 0xc0, 0xb0, 0xbd, 0xb6, 0x83, 0x38, 0xf1, 0x2b, 0x0e, 0x02,
+ 0xc4, 0x08, 0x72, 0xc8, 0x2d, 0x70, 0x02, 0x18, 0x81, 0x81, 0x00, 0x39, 0xe5, 0x14, 0x07, 0x89,
+ 0xe1, 0x93, 0x2f, 0x01, 0x18, 0x87, 0x27, 0x07, 0x08, 0x82, 0x00, 0xb1, 0x93, 0x83, 0x81, 0x20,
+ 0xa8, 0x57, 0x77, 0xf5, 0xb0, 0x7b, 0x1e, 0x92, 0x16, 0x39, 0xe4, 0xc4, 0xa9, 0xaf, 0xbf, 0x57,
+ 0x7d, 0xf5, 0x55, 0xd5, 0x57, 0x5f, 0x7d, 0x45, 0x38, 0xe6, 0x07, 0x5e, 0xe4, 0x99, 0x9e, 0x13,
+ 0xed, 0xfb, 0x38, 0x5c, 0xa0, 0x2d, 0x74, 0x6c, 0x0f, 0x87, 0xdb, 0x2e, 0x8e, 0x16, 0xc4, 0xc7,
+ 0x85, 0xdd, 0x97, 0x9b, 0x73, 0x1d, 0xaf, 0xe3, 0x51, 0xc0, 0x35, 0xf2, 0x8b, 0x7d, 0x6b, 0x9e,
+ 0xf2, 0xe3, 0x70, 0x9b, 0xd2, 0x5e, 0x4b, 0x7e, 0xb1, 0x4f, 0xda, 0x3f, 0x28, 0x50, 0x59, 0x32,
+ 0x4d, 0x2f, 0x76, 0x23, 0x74, 0x1d, 0xc6, 0x3b, 0x81, 0x17, 0xfb, 0x0d, 0xe5, 0x9c, 0x72, 0xb9,
+ 0xbe, 0xd8, 0x5c, 0xc8, 0x91, 0xb0, 0x70, 0x9b, 0x60, 0xe8, 0x0c, 0x11, 0x2d, 0xc0, 0x31, 0x83,
+ 0x11, 0xb7, 0xfd, 0xc0, 0xde, 0x35, 0x22, 0xdc, 0xde, 0xc1, 0xfb, 0x8d, 0xd2, 0x39, 0xe5, 0xf2,
+ 0xa4, 0x3e, 0xcb, 0x3f, 0xb5, 0xd8, 0x97, 0x3b, 0x78, 0x1f, 0x5d, 0x85, 0x59, 0xc3, 0xb1, 0x8d,
+ 0x30, 0x83, 0x5d, 0xa6, 0xd8, 0x33, 0xf4, 0x83, 0x84, 0xfb, 0x2a, 0x9c, 0xf0, 0xe3, 0x4d, 0xc7,
+ 0x36, 0xdb, 0x01, 0x76, 0x2d, 0xfc, 0xf9, 0x5d, 0x2f, 0x0e, 0xdb, 0x21, 0xc6, 0x56, 0x63, 0x8c,
+ 0x12, 0xcc, 0xb1, 0xaf, 0x7a, 0xf2, 0x71, 0x1d, 0x63, 0x4b, 0xfb, 0xa5, 0x02, 0xe3, 0x54, 0x45,
+ 0x74, 0x06, 0x80, 0xd3, 0x13, 0x21, 0x0a, 0xa5, 0xa9, 0x31, 0x08, 0x61, 0x7f, 0x02, 0x26, 0x42,
+ 0x6c, 0x06, 0x38, 0xe2, 0xda, 0xf2, 0x16, 0x21, 0x63, 0xbf, 0xda, 0xa1, 0xdd, 0xe1, 0xba, 0xd5,
+ 0x18, 0x64, 0xdd, 0xee, 0xa0, 0x37, 0x00, 0x68, 0xd7, 0xdb, 0xc4, 0x88, 0x54, 0x93, 0xe9, 0xc5,
+ 0xb3, 0xc5, 0x86, 0x7a, 0xb8, 0xef, 0x63, 0xbd, 0xd6, 0x11, 0x3f, 0xd1, 0x29, 0xa8, 0x86, 0x76,
+ 0xc7, 0x6d, 0xfb, 0xf1, 0x66, 0x63, 0x9c, 0xf2, 0xae, 0x90, 0x76, 0x2b, 0xde, 0x24, 0x9f, 0x1c,
+ 0xdb, 0xdd, 0xa1, 0xda, 0x4e, 0xb0, 0x4f, 0xa4, 0x4d, 0x74, 0x3d, 0x07, 0x93, 0xe2, 0x13, 0xd5,
+ 0xaa, 0x42, 0x3f, 0x03, 0xff, 0xbc, 0x6e, 0x77, 0xb4, 0x5f, 0x29, 0xa0, 0x52, 0x81, 0xff, 0x1f,
+ 0x1b, 0x56, 0xb8, 0xfa, 0xc8, 0xf7, 0x82, 0x68, 0x90, 0x05, 0x64, 0x5d, 0x4a, 0x59, 0x5d, 0x56,
+ 0xe1, 0x58, 0x17, 0x47, 0x86, 0x65, 0x44, 0x46, 0x7b, 0x9b, 0x70, 0x6c, 0x9b, 0xb6, 0x15, 0x36,
+ 0xca, 0xe7, 0xca, 0x97, 0x27, 0x6f, 0x1e, 0x3f, 0x3c, 0x98, 0x9f, 0xbd, 0xc7, 0x3f, 0x53, 0x79,
+ 0xcb, 0x6b, 0x2b, 0xa1, 0x3e, 0xdb, 0xcd, 0x80, 0x6c, 0x2b, 0x64, 0x6c, 0xc2, 0xd0, 0xe8, 0xe0,
+ 0x50, 0x66, 0x33, 0x26, 0xb3, 0x61, 0x9f, 0x33, 0x6c, 0x64, 0x10, 0x61, 0x23, 0x5b, 0x66, 0x3c,
+ 0x63, 0x19, 0xed, 0x27, 0x0a, 0x4c, 0xd1, 0x7e, 0x0b, 0x7d, 0xc8, 0x00, 0xe1, 0x5d, 0xec, 0x46,
+ 0x6c, 0x80, 0x94, 0x3e, 0x03, 0xb4, 0x4a, 0xd0, 0xd8, 0x00, 0x61, 0xf1, 0x13, 0x35, 0xa0, 0xe2,
+ 0x1b, 0xfb, 0x8e, 0x67, 0x58, 0xc2, 0x26, 0xbc, 0x89, 0x54, 0x28, 0xa7, 0x1e, 0x41, 0x7e, 0x22,
+ 0x1d, 0x66, 0x05, 0xbf, 0xb6, 0xe8, 0x3c, 0x75, 0x89, 0xfa, 0xe2, 0x85, 0x5c, 0x89, 0x2d, 0xfe,
+ 0x5b, 0x28, 0xab, 0xab, 0x7e, 0x0f, 0x44, 0x5b, 0xe2, 0xfd, 0x59, 0x75, 0x77, 0xb1, 0xe3, 0xf9,
+ 0x18, 0xcd, 0xc1, 0xb8, 0xeb, 0xb9, 0x26, 0xe6, 0xe3, 0xc7, 0x1a, 0x04, 0x4a, 0x75, 0xe6, 0x4a,
+ 0xb2, 0xc6, 0x5b, 0x63, 0xd5, 0xb2, 0x3a, 0xa6, 0xfd, 0x87, 0x02, 0xd3, 0xdc, 0xae, 0xc4, 0x86,
+ 0x38, 0x08, 0x49, 0xaf, 0xe8, 0x54, 0xc4, 0x01, 0x65, 0x33, 0xa6, 0x8b, 0x26, 0xba, 0x02, 0x35,
+ 0x0b, 0xef, 0xda, 0x26, 0x6e, 0xfb, 0x3b, 0x8c, 0xd9, 0xcd, 0xc9, 0xc3, 0x83, 0xf9, 0xea, 0x0a,
+ 0x05, 0xb6, 0xee, 0xe8, 0x55, 0xf6, 0xb9, 0xb5, 0x93, 0x63, 0x80, 0x7b, 0x50, 0x95, 0xfa, 0x5d,
+ 0xbe, 0x5c, 0x5f, 0x7c, 0x39, 0xb7, 0xdf, 0x59, 0x6d, 0x16, 0x44, 0x67, 0x57, 0xdd, 0x28, 0xd8,
+ 0xd7, 0x13, 0x16, 0xcd, 0x1b, 0x30, 0x95, 0xf9, 0x44, 0x24, 0x0a, 0xcf, 0xad, 0xe9, 0xe4, 0x27,
+ 0xe9, 0xf7, 0xae, 0xe1, 0xc4, 0x98, 0xaa, 0x5a, 0xd3, 0x59, 0xe3, 0x63, 0xa5, 0x8f, 0x2a, 0x5a,
+ 0x03, 0xd4, 0x5e, 0xf3, 0xbe, 0x35, 0x56, 0x55, 0xd4, 0x92, 0xf6, 0x15, 0x05, 0xd4, 0x55, 0xd7,
+ 0x0c, 0xf6, 0xfd, 0x08, 0x5b, 0x5c, 0x15, 0x74, 0x1a, 0x6a, 0xbe, 0x63, 0xd8, 0x6e, 0x84, 0x1f,
+ 0x45, 0xc9, 0xd4, 0x10, 0x80, 0xfc, 0x91, 0x2d, 0x3d, 0xd9, 0xc8, 0xfa, 0x30, 0xc3, 0x85, 0x27,
+ 0x63, 0x7b, 0x09, 0x66, 0xb8, 0xb7, 0xd3, 0xe9, 0x81, 0x83, 0x90, 0xab, 0x32, 0xdd, 0x3d, 0x32,
+ 0x7e, 0x1c, 0x22, 0xbc, 0x92, 0x37, 0x53, 0xf7, 0x28, 0x4b, 0xee, 0xf1, 0xd6, 0x58, 0x75, 0x4c,
+ 0x1d, 0xd7, 0xbe, 0xa4, 0xc0, 0x24, 0x75, 0xf2, 0x65, 0x8f, 0x75, 0xeb, 0x04, 0x94, 0x6c, 0x8b,
+ 0x89, 0xb8, 0x39, 0x71, 0x78, 0x30, 0x5f, 0x5a, 0x5b, 0xd1, 0x4b, 0xb6, 0x85, 0x5e, 0x04, 0xf0,
+ 0x8d, 0x80, 0x4c, 0x1a, 0x32, 0x3d, 0x4b, 0x74, 0x7a, 0x4e, 0x1d, 0x1e, 0xcc, 0xd7, 0x5a, 0x14,
+ 0x4a, 0xa6, 0x65, 0x8d, 0x21, 0xac, 0x59, 0x21, 0xba, 0x08, 0x55, 0xb6, 0x04, 0xfa, 0x3b, 0x4c,
+ 0xea, 0xcd, 0xfa, 0xe1, 0xc1, 0x7c, 0x85, 0xba, 0x6d, 0xeb, 0x8e, 0x5e, 0xa1, 0x1f, 0x5b, 0x3b,
+ 0x5c, 0x09, 0x1d, 0xea, 0x4b, 0x7e, 0x3a, 0x3d, 0x33, 0xfe, 0xa6, 0xf4, 0xf5, 0xb7, 0xc2, 0x4e,
+ 0x6b, 0x1d, 0x40, 0xa4, 0x4b, 0x86, 0x19, 0x2d, 0x59, 0xd6, 0x12, 0xd9, 0x37, 0xc8, 0x7a, 0x36,
+ 0x02, 0xeb, 0x8b, 0x50, 0xe5, 0xfb, 0x90, 0x70, 0x7a, 0xda, 0x05, 0xca, 0x8a, 0x74, 0x81, 0xed,
+ 0x45, 0x3b, 0xda, 0xef, 0x28, 0x30, 0x47, 0xfb, 0xb5, 0x64, 0x59, 0xf7, 0x70, 0x77, 0x13, 0x07,
+ 0x8c, 0x19, 0x91, 0xd5, 0xa5, 0xed, 0x1e, 0x59, 0x0c, 0x89, 0xc8, 0x62, 0x9f, 0x5b, 0x3b, 0xa3,
+ 0xcc, 0xb0, 0x33, 0x00, 0x9c, 0xab, 0xb4, 0xf7, 0x30, 0x08, 0x59, 0xe4, 0x6f, 0xc3, 0x34, 0x23,
+ 0x5a, 0xde, 0x36, 0x6c, 0x97, 0x74, 0xf9, 0x59, 0xa8, 0x99, 0xe4, 0xb7, 0xb4, 0xc0, 0x57, 0x4d,
+ 0xf1, 0x51, 0x9a, 0xf4, 0xa5, 0xcc, 0xa4, 0xd7, 0xbe, 0xa7, 0xc0, 0x09, 0xd1, 0xad, 0x1e, 0x8e,
+ 0x23, 0x18, 0xf1, 0x23, 0x30, 0x6d, 0xe1, 0x30, 0x6a, 0xa7, 0x86, 0x60, 0xbd, 0x53, 0x0f, 0x0f,
+ 0xe6, 0x27, 0x57, 0x70, 0x18, 0x25, 0xc6, 0x98, 0xb4, 0xd2, 0xd6, 0x8e, 0xbc, 0xc4, 0x96, 0x33,
+ 0x4b, 0x2c, 0xd1, 0xeb, 0xdc, 0xbd, 0xd8, 0x89, 0x6c, 0x86, 0x2b, 0x54, 0xa4, 0xc3, 0xa2, 0xe3,
+ 0xd0, 0x73, 0x76, 0x7b, 0x57, 0xac, 0xfe, 0x1a, 0x5e, 0x80, 0x69, 0x36, 0xcc, 0x01, 0x27, 0xe6,
+ 0x8e, 0x34, 0x65, 0x64, 0x38, 0xce, 0x43, 0x5d, 0x44, 0x25, 0x9e, 0xb7, 0xc5, 0x95, 0x02, 0x1e,
+ 0x8f, 0x78, 0xde, 0x96, 0xf6, 0x35, 0x05, 0x4e, 0x65, 0xf4, 0x32, 0xdc, 0x68, 0xc9, 0xea, 0xda,
+ 0xae, 0xee, 0x39, 0x78, 0x14, 0x85, 0x3e, 0x01, 0xb3, 0x1d, 0x42, 0x8c, 0xf1, 0x11, 0xab, 0x1d,
+ 0x3b, 0x3c, 0x98, 0x9f, 0xb9, 0xcd, 0x3e, 0x26, 0x86, 0x9b, 0xe9, 0x64, 0x00, 0x3b, 0xda, 0x2a,
+ 0x34, 0x24, 0x45, 0xd6, 0x5c, 0x3b, 0xb2, 0x0d, 0x87, 0x35, 0x46, 0xf0, 0x49, 0xcd, 0x80, 0x73,
+ 0x89, 0x71, 0x2d, 0xcb, 0x8e, 0x6c, 0xcf, 0x35, 0x9c, 0x6c, 0x24, 0x35, 0x4a, 0xb7, 0x10, 0x8c,
+ 0xd1, 0xc0, 0x8c, 0x59, 0x97, 0xfe, 0xd6, 0x2c, 0x38, 0xcf, 0x42, 0x45, 0xdc, 0xf5, 0x76, 0xf1,
+ 0x87, 0x25, 0xe5, 0x7d, 0x40, 0x3c, 0x7a, 0xa5, 0xc2, 0xde, 0xf2, 0x6c, 0x77, 0x34, 0xa6, 0x49,
+ 0xcc, 0x5b, 0x1a, 0x32, 0xe6, 0xd5, 0x30, 0xa8, 0xb2, 0xc8, 0xbb, 0x78, 0x2b, 0x1a, 0x71, 0xe9,
+ 0x49, 0x56, 0xcf, 0x52, 0xf1, 0xea, 0xa9, 0xbd, 0x05, 0x67, 0xb8, 0x18, 0xbe, 0xd4, 0xe9, 0xf8,
+ 0xfd, 0x18, 0x87, 0xd1, 0x8a, 0x1d, 0x1a, 0x9b, 0xce, 0x48, 0x9d, 0xd4, 0xd6, 0xe0, 0x74, 0x2e,
+ 0xaf, 0x55, 0x77, 0x64, 0x56, 0x5f, 0x55, 0xe0, 0x7c, 0x2e, 0x2f, 0x1d, 0x6f, 0xe1, 0x00, 0xbb,
+ 0x26, 0xd6, 0x71, 0x88, 0x47, 0xb2, 0x48, 0x71, 0xa0, 0x5f, 0xea, 0x13, 0xe8, 0xff, 0x4c, 0x29,
+ 0x30, 0xd0, 0xaa, 0xfb, 0x7e, 0x8c, 0xe3, 0xd1, 0xbc, 0x60, 0xc8, 0x41, 0x41, 0x9f, 0x20, 0x4b,
+ 0x2a, 0x15, 0x46, 0x57, 0x89, 0xa2, 0x68, 0x60, 0x7d, 0xdb, 0x08, 0x30, 0x31, 0xad, 0xd0, 0x4c,
+ 0x50, 0xa1, 0xe7, 0x60, 0xd2, 0xdb, 0x73, 0xb3, 0xd1, 0xe2, 0xa4, 0x5e, 0xf7, 0xf6, 0xdc, 0x24,
+ 0x4e, 0x88, 0xe0, 0x54, 0x6e, 0xbf, 0xd6, 0xb1, 0x3b, 0x92, 0x59, 0x5f, 0x04, 0xe0, 0x52, 0xd3,
+ 0x5e, 0xd1, 0x4d, 0x9d, 0xb3, 0x6d, 0xdd, 0xd1, 0x6b, 0x1c, 0xa1, 0xb5, 0xa3, 0xfd, 0x63, 0x91,
+ 0x39, 0x75, 0x6c, 0x62, 0x7b, 0x77, 0x34, 0x73, 0x8e, 0x24, 0x1a, 0x7d, 0x04, 0x4e, 0x0a, 0xec,
+ 0x5e, 0x07, 0x60, 0x4b, 0xf1, 0x71, 0x53, 0x68, 0xd4, 0xb3, 0x74, 0xa8, 0x82, 0xae, 0xc7, 0x9e,
+ 0x33, 0x1c, 0x9e, 0xd8, 0x74, 0x1f, 0xce, 0x16, 0x4d, 0x26, 0xd3, 0x08, 0xac, 0x0f, 0xb1, 0x77,
+ 0xda, 0x9f, 0x14, 0x19, 0x76, 0xc9, 0x34, 0x31, 0x89, 0x48, 0x3f, 0x3c, 0xc3, 0x0e, 0x19, 0xa8,
+ 0x69, 0x3e, 0x1c, 0xcf, 0x6a, 0x78, 0xd3, 0xf1, 0xcc, 0x9d, 0x0f, 0xd3, 0x28, 0x01, 0x9c, 0xcc,
+ 0x4a, 0xdc, 0x70, 0x37, 0x3f, 0x6c, 0x99, 0xbf, 0xab, 0x40, 0x83, 0x0b, 0x5d, 0xc7, 0x01, 0x61,
+ 0xf1, 0xd0, 0xdb, 0xc1, 0xee, 0x92, 0x35, 0xe2, 0xf0, 0xdf, 0x82, 0xa9, 0x90, 0xd1, 0xb7, 0x23,
+ 0xc2, 0x80, 0xef, 0x1c, 0xcf, 0xe5, 0xaf, 0x04, 0x92, 0x24, 0x7d, 0x32, 0x94, 0x5a, 0x9a, 0x07,
+ 0xcd, 0x1c, 0x75, 0xd8, 0x76, 0x39, 0xea, 0xe2, 0x45, 0x15, 0x69, 0xdb, 0x6c, 0xc5, 0xac, 0xb1,
+ 0x61, 0xa6, 0xec, 0xd6, 0x56, 0xf4, 0x0a, 0xfd, 0xb8, 0x66, 0x69, 0x3f, 0x14, 0x39, 0x02, 0x1d,
+ 0xfb, 0x8e, 0x6d, 0x1a, 0x91, 0xed, 0x76, 0x46, 0x91, 0xb3, 0x02, 0xc8, 0x88, 0xa3, 0x6d, 0xec,
+ 0x46, 0x94, 0xd8, 0x73, 0xdb, 0x71, 0xe0, 0x70, 0x89, 0xf4, 0x30, 0xbf, 0x94, 0xf9, 0xba, 0xa1,
+ 0xdf, 0xd5, 0x67, 0xb3, 0x04, 0x1b, 0x81, 0x83, 0x5e, 0x02, 0x14, 0x08, 0xf9, 0x9e, 0xdb, 0x26,
+ 0x26, 0xc1, 0x01, 0x75, 0xcf, 0x9a, 0x3e, 0x2b, 0x7d, 0x59, 0xa7, 0x1f, 0xb4, 0xbb, 0x30, 0xcb,
+ 0xcd, 0xc3, 0x92, 0x1a, 0x2b, 0xe4, 0xa0, 0x58, 0x83, 0x0a, 0x9f, 0x44, 0xcd, 0x17, 0x61, 0x9c,
+ 0x74, 0x67, 0x1f, 0x9d, 0x87, 0x29, 0x4c, 0x31, 0xb0, 0xd5, 0xa6, 0x4b, 0x01, 0x0b, 0x87, 0x27,
+ 0x05, 0x90, 0x10, 0x6a, 0xbf, 0x9a, 0x80, 0x93, 0x9c, 0xdd, 0x6d, 0x4c, 0x7c, 0x6f, 0xcb, 0xee,
+ 0xc4, 0x01, 0x95, 0x27, 0x33, 0xfd, 0x60, 0x42, 0x70, 0x7d, 0x11, 0x20, 0x49, 0x70, 0x09, 0xfb,
+ 0x50, 0x17, 0xe3, 0x43, 0x47, 0x5c, 0x4c, 0xa4, 0xb9, 0x46, 0x0a, 0xf5, 0x3f, 0x0e, 0xaa, 0x60,
+ 0xdc, 0x33, 0x47, 0xd1, 0xe1, 0xc1, 0xfc, 0xb4, 0x1c, 0x61, 0xb4, 0xee, 0xe8, 0xd3, 0x86, 0xdc,
+ 0xde, 0x41, 0xe7, 0xa1, 0xe2, 0x63, 0x1c, 0x90, 0x11, 0x1f, 0xa3, 0xf6, 0x87, 0xc3, 0x83, 0xf9,
+ 0x89, 0x16, 0xc6, 0xc1, 0xda, 0x8a, 0x3e, 0x41, 0x3e, 0xad, 0x59, 0xe4, 0x88, 0xeb, 0xd8, 0x61,
+ 0x84, 0x5d, 0x72, 0xae, 0x1c, 0x3f, 0x57, 0xbe, 0x5c, 0xd3, 0x53, 0x00, 0xfa, 0x0c, 0xd4, 0x37,
+ 0x1d, 0xdc, 0xc6, 0x2c, 0x04, 0xa0, 0x19, 0xa7, 0xe9, 0xc5, 0xd7, 0xfb, 0x39, 0x71, 0xaf, 0xc5,
+ 0x16, 0xd6, 0x71, 0x44, 0x7c, 0x68, 0x3d, 0x32, 0x22, 0xac, 0xc3, 0xa6, 0x83, 0x45, 0x3c, 0x61,
+ 0x82, 0xba, 0x67, 0x6f, 0xd9, 0x6d, 0x7f, 0xd1, 0x4f, 0x04, 0x54, 0x9e, 0x54, 0xc0, 0x34, 0x61,
+ 0xd9, 0x5a, 0xf4, 0x85, 0x90, 0xf7, 0x60, 0xb2, 0x6b, 0xb9, 0x61, 0x22, 0xa0, 0xfa, 0xa4, 0x02,
+ 0xea, 0x84, 0x9d, 0xe0, 0xfe, 0x1b, 0x30, 0x15, 0x60, 0xc7, 0xd8, 0x4f, 0xd8, 0xd7, 0x9e, 0x94,
+ 0xfd, 0x24, 0xe5, 0x27, 0xf8, 0x3f, 0x84, 0x59, 0xe1, 0x2a, 0x71, 0xb8, 0xcd, 0x57, 0x12, 0xa0,
+ 0x2b, 0xc9, 0xe5, 0xfc, 0x0c, 0x43, 0x1c, 0x6e, 0x73, 0x39, 0x7c, 0x4b, 0x0e, 0xf4, 0x19, 0xee,
+ 0x4e, 0x71, 0xb8, 0x4d, 0x67, 0x3b, 0xba, 0x07, 0x48, 0xe6, 0xca, 0x27, 0x57, 0x9d, 0xb2, 0x9d,
+ 0xef, 0xcb, 0x16, 0x07, 0xba, 0x9a, 0x72, 0xe3, 0x93, 0xef, 0x36, 0x4c, 0xca, 0x5d, 0x40, 0x75,
+ 0xa8, 0x6c, 0xb8, 0x3b, 0xae, 0xb7, 0xe7, 0xaa, 0xcf, 0x90, 0x06, 0xef, 0x8c, 0xaa, 0xa0, 0x49,
+ 0xa8, 0x8a, 0xc0, 0x54, 0x2d, 0xa1, 0x19, 0xa8, 0x6f, 0xb8, 0xc6, 0xae, 0x61, 0x3b, 0x04, 0xa2,
+ 0x96, 0xb5, 0x2f, 0xc0, 0xc9, 0x82, 0x68, 0x51, 0x9e, 0x76, 0xef, 0x88, 0x59, 0x57, 0x1c, 0x11,
+ 0x2a, 0xc5, 0x11, 0x21, 0x39, 0x57, 0x8a, 0xc1, 0x22, 0x73, 0xaf, 0xaa, 0x8b, 0xa6, 0xf6, 0x02,
+ 0x1c, 0xcf, 0x0d, 0xa2, 0x65, 0xe1, 0x15, 0x2e, 0x5c, 0xfb, 0x2c, 0xcc, 0xe5, 0x45, 0xc9, 0x32,
+ 0xee, 0x1b, 0x4f, 0xa4, 0xa8, 0xb6, 0x0d, 0xa7, 0x7b, 0xad, 0x11, 0xe2, 0x7c, 0x93, 0x3c, 0xa1,
+ 0xa4, 0x6f, 0x28, 0x49, 0xa6, 0x24, 0x8d, 0x22, 0xad, 0x66, 0x37, 0x11, 0x20, 0x47, 0xb4, 0xca,
+ 0x53, 0x89, 0x68, 0x4b, 0x47, 0x22, 0xda, 0xd4, 0xb4, 0x9f, 0xee, 0x35, 0x2d, 0x8b, 0x81, 0x9a,
+ 0xaf, 0xa5, 0xfa, 0x64, 0xf7, 0x74, 0xa5, 0xff, 0x9e, 0x9e, 0x72, 0x7e, 0x37, 0x67, 0x84, 0x49,
+ 0x64, 0xf7, 0x14, 0x58, 0xb7, 0x60, 0x52, 0x0e, 0x8b, 0x9e, 0x02, 0x47, 0x1d, 0xa6, 0xb3, 0x61,
+ 0xcf, 0x53, 0xe0, 0xf9, 0x36, 0x1c, 0x13, 0x29, 0x31, 0x9e, 0x0f, 0xa3, 0x23, 0xfd, 0x72, 0xca,
+ 0x58, 0x8e, 0x06, 0x95, 0xe2, 0x68, 0x30, 0x65, 0xf9, 0x10, 0x4e, 0xf4, 0x26, 0x63, 0x96, 0x03,
+ 0x6c, 0x44, 0x19, 0x07, 0xbd, 0x26, 0x1c, 0x74, 0x48, 0xf6, 0xda, 0x7b, 0x30, 0xd7, 0xcb, 0x95,
+ 0x9c, 0xda, 0x9b, 0x37, 0x52, 0x4d, 0x47, 0xbe, 0x87, 0x4a, 0x75, 0x5e, 0x87, 0xe3, 0xbd, 0xdc,
+ 0xef, 0x62, 0x63, 0x17, 0x3f, 0x91, 0x21, 0x4c, 0xb8, 0x70, 0x24, 0x2b, 0x25, 0x27, 0x90, 0x88,
+ 0xaf, 0x39, 0x5e, 0xf8, 0x64, 0x42, 0xbe, 0xa6, 0xc0, 0xd9, 0xa3, 0xb9, 0x2f, 0x9e, 0x63, 0xa2,
+ 0x79, 0xa1, 0xe6, 0x7b, 0x23, 0xb3, 0xcf, 0xe6, 0x84, 0x4a, 0xfd, 0x72, 0x42, 0xa9, 0x26, 0xdf,
+ 0xca, 0xc9, 0xc2, 0xad, 0xb9, 0xbb, 0x76, 0x44, 0x37, 0x35, 0xee, 0x02, 0x8f, 0xd1, 0xd5, 0xd7,
+ 0x85, 0xab, 0x8c, 0x3c, 0xbe, 0xda, 0xd7, 0x15, 0x98, 0x91, 0xb2, 0xc8, 0xd4, 0xb5, 0xdf, 0x1e,
+ 0xdd, 0x1a, 0x85, 0x97, 0x3b, 0xec, 0xe6, 0xa4, 0xa9, 0x09, 0x0d, 0x4f, 0x41, 0xd9, 0x4c, 0x32,
+ 0xe5, 0x95, 0xc3, 0x83, 0xf9, 0xf2, 0xf2, 0xda, 0x8a, 0x4e, 0x60, 0x64, 0x9c, 0xa6, 0xa9, 0x2a,
+ 0x34, 0x15, 0xfd, 0xbf, 0xa9, 0xc9, 0x0f, 0x15, 0x40, 0x99, 0xbb, 0x2f, 0x9a, 0xeb, 0x27, 0xe7,
+ 0x13, 0x76, 0x01, 0x66, 0x7a, 0xe9, 0xed, 0x46, 0xd1, 0xf9, 0x44, 0xbe, 0x1e, 0xd0, 0x27, 0xb1,
+ 0x7c, 0x59, 0xf0, 0xa6, 0x74, 0xb9, 0xc3, 0x8e, 0x38, 0x5a, 0xf1, 0x40, 0x25, 0xf7, 0x1e, 0x09,
+ 0x4d, 0x7a, 0x45, 0x55, 0x96, 0xae, 0xa8, 0xb4, 0xbf, 0x54, 0x60, 0x96, 0x53, 0xb0, 0xbb, 0x90,
+ 0xa7, 0xaa, 0xf3, 0x1b, 0x50, 0x11, 0x17, 0x29, 0x4c, 0xe5, 0xf3, 0x43, 0xdc, 0x47, 0xe9, 0x82,
+ 0x46, 0xbe, 0x71, 0x28, 0x67, 0x6f, 0x1c, 0xfe, 0x33, 0x55, 0x9b, 0x75, 0xef, 0xae, 0x1d, 0x46,
+ 0xcd, 0x9f, 0x2b, 0xa3, 0x8f, 0xfc, 0x45, 0xa8, 0x86, 0xb6, 0x6b, 0x62, 0x71, 0x5a, 0xe3, 0x78,
+ 0xeb, 0x04, 0x46, 0x4e, 0x6b, 0xf4, 0xe3, 0x9a, 0x85, 0x9e, 0x85, 0x1a, 0xc3, 0x73, 0xbd, 0x3d,
+ 0xaa, 0x4d, 0x55, 0x67, 0x84, 0xf7, 0xbd, 0x3d, 0xc2, 0x24, 0x76, 0x23, 0xdb, 0x11, 0x07, 0x00,
+ 0xce, 0x64, 0x83, 0xc0, 0x08, 0x13, 0xfa, 0x91, 0x31, 0x61, 0x78, 0x84, 0xc9, 0x38, 0x63, 0x42,
+ 0x01, 0x84, 0xc9, 0x79, 0x12, 0xe2, 0xee, 0xe2, 0x20, 0xc4, 0x6d, 0x2f, 0xb0, 0x70, 0x40, 0xcf,
+ 0x00, 0x55, 0x12, 0xa7, 0x52, 0xe0, 0x03, 0x02, 0x4b, 0x2f, 0x96, 0xb9, 0xcd, 0xfe, 0xaf, 0xf4,
+ 0xfb, 0xbf, 0x15, 0xa8, 0xf1, 0x95, 0x6f, 0xcb, 0x6b, 0xb6, 0x47, 0xef, 0xef, 0x48, 0xc9, 0x89,
+ 0xe6, 0x37, 0x95, 0xc7, 0x5e, 0x1c, 0x47, 0x58, 0xe3, 0xb3, 0x07, 0xd4, 0x72, 0xdf, 0x44, 0xef,
+ 0xe7, 0x60, 0x6a, 0xc9, 0x8c, 0x68, 0x35, 0x06, 0x95, 0xd6, 0x6c, 0x8d, 0x6e, 0x83, 0x33, 0x00,
+ 0x8e, 0x67, 0x1a, 0x4e, 0xdb, 0x73, 0x9d, 0x7d, 0x1e, 0x94, 0xd7, 0x28, 0xe4, 0x81, 0xeb, 0xec,
+ 0xa7, 0x3b, 0xce, 0x3d, 0x98, 0x59, 0xc1, 0x46, 0x46, 0xda, 0x93, 0x6c, 0xa5, 0xdf, 0x1a, 0xe7,
+ 0x93, 0x95, 0x75, 0x8b, 0x9c, 0x5d, 0xe2, 0xf0, 0x71, 0x38, 0x7e, 0xbf, 0x2c, 0x46, 0xe5, 0x13,
+ 0x30, 0x26, 0xd5, 0x13, 0xbc, 0x50, 0x3c, 0x28, 0xb2, 0xc8, 0x05, 0x5a, 0x5c, 0x40, 0x09, 0xf3,
+ 0x2f, 0xec, 0x9b, 0x3f, 0x56, 0x60, 0x8a, 0x9c, 0xda, 0x97, 0x3d, 0xd7, 0xc5, 0x66, 0x84, 0x2d,
+ 0xf9, 0x64, 0xaf, 0x14, 0x9e, 0xec, 0x47, 0xc8, 0x33, 0xb4, 0x00, 0xa2, 0xc0, 0x70, 0x43, 0xdf,
+ 0x0b, 0x22, 0x56, 0xc0, 0x31, 0xbd, 0x78, 0x7d, 0x58, 0xf5, 0x05, 0xa1, 0x2e, 0xf1, 0x40, 0x27,
+ 0x60, 0xa2, 0x6b, 0x58, 0x56, 0xc0, 0xea, 0x38, 0x6a, 0x3a, 0x6f, 0x35, 0x5f, 0x03, 0x95, 0xa8,
+ 0xa9, 0x63, 0x93, 0x75, 0xc6, 0x76, 0x3b, 0x43, 0xf5, 0x46, 0x10, 0x92, 0x28, 0x6a, 0x24, 0x33,
+ 0x68, 0x9b, 0x30, 0x46, 0x6b, 0x36, 0x66, 0xa0, 0x4e, 0xfe, 0xa6, 0x47, 0xd3, 0x06, 0xcc, 0x11,
+ 0x40, 0x2f, 0x57, 0x55, 0x41, 0xc7, 0x61, 0x56, 0x7c, 0x49, 0x6c, 0xae, 0x96, 0x64, 0x02, 0x59,
+ 0x7f, 0xb5, 0xac, 0xad, 0x42, 0x2d, 0x31, 0x03, 0x9a, 0x06, 0x78, 0xe8, 0x47, 0xa9, 0x1c, 0x80,
+ 0x89, 0x87, 0x7e, 0x74, 0x77, 0xe9, 0xbe, 0xaa, 0xf0, 0xdf, 0xef, 0x2c, 0xdd, 0x57, 0x4b, 0x48,
+ 0x85, 0xc9, 0x87, 0x7e, 0xd4, 0x0a, 0xbc, 0x47, 0x76, 0xd7, 0x8e, 0xf6, 0xd5, 0xb2, 0xf6, 0x77,
+ 0x0a, 0x71, 0xf1, 0xcd, 0xb8, 0x43, 0xd6, 0x4f, 0x6a, 0xe9, 0x50, 0x8e, 0xa2, 0xff, 0x4c, 0x19,
+ 0x31, 0x8c, 0x46, 0x77, 0x33, 0x75, 0x48, 0xa5, 0x61, 0xea, 0x90, 0xd8, 0xf2, 0x93, 0x5b, 0x96,
+ 0x94, 0x5d, 0xac, 0xca, 0x03, 0x32, 0xa9, 0xbf, 0x57, 0x86, 0x13, 0xb4, 0x33, 0x6b, 0x6e, 0xe8,
+ 0x63, 0x93, 0xf5, 0x67, 0x3d, 0xf2, 0x02, 0xdc, 0xfc, 0xfa, 0x63, 0xec, 0x0c, 0x1b, 0x50, 0x75,
+ 0xbc, 0x8e, 0xdc, 0x91, 0x97, 0x72, 0x3b, 0x72, 0x44, 0xe4, 0x5d, 0xaf, 0x43, 0xfb, 0x45, 0xd9,
+ 0xf2, 0x86, 0x5e, 0x71, 0xd8, 0x8f, 0xe6, 0x2f, 0x94, 0xc1, 0x31, 0x14, 0xba, 0x06, 0x75, 0x5e,
+ 0xf9, 0x60, 0xa6, 0xa5, 0x0f, 0xd3, 0x87, 0x07, 0xf3, 0xc0, 0x4a, 0x1f, 0x68, 0x49, 0x12, 0x2f,
+ 0x8e, 0xa0, 0xb5, 0x48, 0xf7, 0xa5, 0xca, 0x28, 0xa9, 0xce, 0xa8, 0x3c, 0x54, 0x9d, 0x51, 0x52,
+ 0x22, 0x95, 0x80, 0xb2, 0x53, 0x79, 0x6c, 0x50, 0x3d, 0x84, 0x88, 0x19, 0x27, 0xb2, 0xf7, 0xe6,
+ 0x3e, 0x00, 0x35, 0xce, 0x63, 0x2f, 0x9d, 0xf2, 0x29, 0x8e, 0xcf, 0xbb, 0xb0, 0xa1, 0x90, 0xe9,
+ 0xcd, 0x08, 0xd8, 0xc4, 0x0b, 0xf5, 0x0a, 0x9b, 0x79, 0xa1, 0xf6, 0xa7, 0x25, 0x98, 0x5b, 0x8a,
+ 0xa3, 0xed, 0xd5, 0x47, 0xe6, 0xb6, 0xe1, 0x76, 0xb0, 0x8e, 0x43, 0xdf, 0x73, 0x43, 0x8c, 0x9e,
+ 0x83, 0x49, 0xc3, 0x34, 0x71, 0x18, 0xf2, 0x94, 0x16, 0xab, 0xdd, 0xa9, 0x33, 0x18, 0x4b, 0x52,
+ 0xcd, 0xc1, 0x78, 0x68, 0x7a, 0x7e, 0x52, 0xc3, 0x43, 0x1b, 0x74, 0x81, 0x0c, 0x02, 0x4f, 0xa4,
+ 0x82, 0x59, 0x03, 0xbd, 0x00, 0xb3, 0xf4, 0x47, 0xdb, 0xc2, 0xa1, 0x19, 0xd8, 0x3e, 0x39, 0x81,
+ 0xb0, 0x94, 0xa7, 0xae, 0xd2, 0x0f, 0x2b, 0x29, 0x1c, 0xad, 0x43, 0x95, 0x67, 0xd8, 0x59, 0xbe,
+ 0xb3, 0xbe, 0xf8, 0x5a, 0xee, 0x80, 0xe4, 0x29, 0x2e, 0x72, 0x78, 0x21, 0x2f, 0x4a, 0x12, 0x8c,
+ 0x9a, 0x37, 0x60, 0x2a, 0xf3, 0x69, 0xa4, 0xa2, 0xa4, 0x1f, 0x29, 0xd0, 0xa0, 0x23, 0x43, 0x44,
+ 0x72, 0x36, 0xeb, 0x38, 0xa2, 0x76, 0x68, 0x7e, 0x4b, 0x91, 0xd3, 0x30, 0xe3, 0xa9, 0xbd, 0xea,
+ 0x8b, 0x57, 0x86, 0xd6, 0x5b, 0x67, 0x74, 0x4f, 0x27, 0x39, 0x9f, 0x6e, 0xa1, 0xbf, 0x09, 0x6a,
+ 0x6f, 0xca, 0x07, 0x9d, 0x80, 0x52, 0xe2, 0x46, 0xb4, 0x7a, 0xa8, 0x75, 0x47, 0x2f, 0xf9, 0x8f,
+ 0x79, 0x7f, 0x8b, 0x9a, 0xd2, 0xf1, 0x82, 0x05, 0xdb, 0x49, 0x5b, 0x73, 0xe0, 0xb4, 0x7c, 0x27,
+ 0xb2, 0x1e, 0xfb, 0x2c, 0x87, 0xcf, 0x81, 0xc4, 0xc9, 0x92, 0x2b, 0x18, 0xb1, 0x2b, 0xd7, 0xf4,
+ 0xba, 0xb8, 0x5e, 0x61, 0xf3, 0x4a, 0x15, 0x28, 0xd8, 0xb5, 0x7c, 0xcf, 0xe6, 0x5b, 0x6f, 0x4d,
+ 0x9f, 0xe1, 0xf0, 0x55, 0x0e, 0xd6, 0xfe, 0x55, 0x81, 0x49, 0x59, 0x1c, 0x19, 0x4f, 0xd9, 0x79,
+ 0x9f, 0xa6, 0x85, 0xd1, 0x67, 0x01, 0x85, 0xa2, 0x3b, 0xed, 0xc4, 0x5b, 0xcb, 0x7d, 0x8a, 0xe7,
+ 0xfa, 0x59, 0x42, 0x9f, 0x0d, 0x7b, 0x20, 0x21, 0x3a, 0x0b, 0x80, 0x1f, 0xf9, 0x36, 0x4b, 0x41,
+ 0xd3, 0xb9, 0x52, 0xd6, 0x25, 0x88, 0xf6, 0xdb, 0x0a, 0x9c, 0x94, 0xdc, 0x71, 0xd9, 0xeb, 0xfa,
+ 0x0e, 0x8e, 0xf0, 0x2d, 0xc7, 0xdb, 0x6b, 0xbe, 0x91, 0x7a, 0xe4, 0x22, 0x4c, 0x9a, 0x86, 0xe3,
+ 0x6c, 0x1a, 0xe6, 0x0e, 0xed, 0x28, 0xdb, 0x86, 0x67, 0x0e, 0x0f, 0xe6, 0xeb, 0xcb, 0x1c, 0x4e,
+ 0xba, 0x58, 0x17, 0x48, 0xc4, 0x7d, 0xe4, 0x65, 0x24, 0xb9, 0x92, 0x52, 0xfa, 0x5c, 0x49, 0xfd,
+ 0x48, 0x81, 0x63, 0x92, 0x2e, 0x6b, 0xae, 0x1d, 0x51, 0x3d, 0xee, 0x65, 0x96, 0x30, 0x62, 0x45,
+ 0x49, 0x07, 0x56, 0xaa, 0x15, 0x47, 0xdb, 0x44, 0x7e, 0x85, 0x7c, 0x24, 0x86, 0x6d, 0x4a, 0x93,
+ 0xbf, 0x4c, 0x03, 0x93, 0x74, 0x0e, 0xb7, 0xa4, 0x9d, 0x20, 0xe5, 0x43, 0x77, 0x02, 0xc2, 0x83,
+ 0xc0, 0xc8, 0x16, 0x18, 0x62, 0x33, 0x0e, 0x70, 0x32, 0xac, 0x55, 0xb6, 0x05, 0xae, 0x53, 0x28,
+ 0xc1, 0xab, 0x31, 0x84, 0x8d, 0xc0, 0xd1, 0x7e, 0xa1, 0xc0, 0x85, 0xe5, 0x00, 0x5b, 0x64, 0x70,
+ 0x0d, 0xe7, 0x53, 0x38, 0xb0, 0xb7, 0xa4, 0x7b, 0x2b, 0xb9, 0x2b, 0x52, 0xae, 0xf5, 0x1a, 0x08,
+ 0x17, 0x95, 0x7a, 0x43, 0x37, 0x1b, 0x4e, 0x44, 0x84, 0x00, 0x47, 0x21, 0x7d, 0xca, 0x16, 0xf0,
+ 0x96, 0x7a, 0x0b, 0x78, 0x11, 0x8c, 0x39, 0xb6, 0xbb, 0xc3, 0x57, 0x4c, 0xfa, 0xfb, 0x43, 0xe8,
+ 0xea, 0x77, 0x15, 0xb8, 0xd2, 0xb7, 0xab, 0xc3, 0x79, 0x90, 0x9d, 0xef, 0x41, 0x6b, 0xb2, 0x07,
+ 0xd9, 0xcd, 0x4b, 0x42, 0xfd, 0xb3, 0x00, 0x36, 0x15, 0xb9, 0x65, 0xf3, 0xa2, 0xd5, 0x9a, 0x2e,
+ 0x41, 0xb4, 0x2f, 0x97, 0xe0, 0x24, 0xd3, 0x05, 0x5b, 0xa9, 0x76, 0x21, 0x3d, 0x9e, 0x7e, 0x45,
+ 0x5a, 0x58, 0x5f, 0x80, 0xd9, 0x2d, 0xdb, 0x89, 0xe8, 0x96, 0xd6, 0xc3, 0x4e, 0x65, 0x1f, 0xd6,
+ 0x12, 0x38, 0x39, 0x19, 0x0a, 0xe4, 0x30, 0x8c, 0x79, 0xb9, 0x58, 0x4d, 0x9f, 0xe4, 0x88, 0x14,
+ 0x86, 0x2e, 0xc1, 0x0c, 0x7e, 0x64, 0x3a, 0xb1, 0x85, 0xdb, 0x74, 0x56, 0xf1, 0x32, 0x85, 0xaa,
+ 0x3e, 0xcd, 0xc1, 0xab, 0x0c, 0xda, 0x34, 0x44, 0x5f, 0x3e, 0x0d, 0x60, 0x26, 0x2a, 0xf2, 0x15,
+ 0xfe, 0xa3, 0xf9, 0x2b, 0x3c, 0xbb, 0xe6, 0x3b, 0xda, 0x31, 0x1d, 0x77, 0xec, 0x30, 0xc2, 0x01,
+ 0xb6, 0x74, 0x89, 0x97, 0xf6, 0x0d, 0x25, 0xb9, 0x1e, 0x65, 0x9b, 0x2b, 0xed, 0xbf, 0x14, 0x58,
+ 0x3a, 0x23, 0xce, 0x48, 0x74, 0x03, 0x2a, 0xdc, 0x01, 0x87, 0xbf, 0xd7, 0x16, 0x14, 0xda, 0x6f,
+ 0xf5, 0x68, 0xb3, 0xec, 0x59, 0x38, 0x33, 0x31, 0x95, 0xec, 0xc4, 0x44, 0x17, 0x60, 0xda, 0xf4,
+ 0x2c, 0xdc, 0x36, 0xb7, 0x0d, 0xc7, 0xc1, 0x6e, 0x47, 0x6c, 0xa1, 0x53, 0x04, 0xba, 0x2c, 0x80,
+ 0x19, 0xe5, 0xcb, 0x7d, 0x96, 0x93, 0x0f, 0x14, 0x98, 0xd7, 0xb3, 0x57, 0xc8, 0xf4, 0xba, 0x8c,
+ 0xd9, 0x8e, 0x45, 0x47, 0xef, 0x66, 0x96, 0x96, 0xa1, 0x6c, 0x32, 0x64, 0x75, 0x50, 0xba, 0x7b,
+ 0x7e, 0x51, 0x81, 0x73, 0x79, 0x7a, 0x30, 0x08, 0x3f, 0xe1, 0x3e, 0x51, 0xc2, 0x7b, 0x5e, 0x8c,
+ 0xeb, 0x09, 0x28, 0x79, 0x6c, 0x53, 0xae, 0xb2, 0x4d, 0xf9, 0xc1, 0x1d, 0xbd, 0xe4, 0xed, 0x68,
+ 0x3f, 0x02, 0x80, 0xf5, 0xfd, 0x30, 0xc2, 0x5d, 0x9a, 0xc0, 0x90, 0x5c, 0xe2, 0xdf, 0x93, 0xb8,
+ 0x78, 0x09, 0x2a, 0x7e, 0xe0, 0x91, 0xc0, 0x8c, 0x0b, 0xbe, 0x94, 0x3f, 0xd6, 0x09, 0x9b, 0x85,
+ 0x16, 0x43, 0xd7, 0x05, 0x1d, 0x7a, 0x13, 0xca, 0xfe, 0xa2, 0xdf, 0x37, 0xd9, 0x26, 0x93, 0x2f,
+ 0xb6, 0xd8, 0x52, 0xd4, 0x5a, 0x6c, 0xe9, 0x84, 0x10, 0xdd, 0x87, 0x8a, 0x17, 0x6c, 0xda, 0x91,
+ 0xb5, 0xc9, 0x0b, 0xaa, 0x06, 0xaa, 0xf0, 0x80, 0xa0, 0xaf, 0xdc, 0x64, 0x43, 0xc0, 0x1b, 0xba,
+ 0x60, 0x42, 0xb6, 0xee, 0x3d, 0x23, 0x70, 0xc5, 0xd9, 0x94, 0x35, 0x9a, 0xff, 0xa6, 0x80, 0x40,
+ 0x45, 0x56, 0x7a, 0xf1, 0x9e, 0xc4, 0x1f, 0xac, 0xf7, 0xaf, 0x0f, 0x29, 0x7a, 0x41, 0x1e, 0x5a,
+ 0x7a, 0x52, 0xd6, 0x67, 0x38, 0xcb, 0xe4, 0xca, 0xeb, 0x0b, 0x30, 0x7b, 0x04, 0x8b, 0xcc, 0x04,
+ 0x3f, 0xf0, 0x3a, 0x81, 0x30, 0x78, 0x59, 0x4f, 0xda, 0x34, 0xf5, 0x68, 0x3c, 0xb2, 0xbb, 0x71,
+ 0x97, 0x1a, 0xb3, 0xac, 0x8b, 0x26, 0xa1, 0xda, 0x8c, 0xb7, 0xb6, 0xb0, 0x58, 0x68, 0xca, 0x7a,
+ 0xd2, 0x26, 0x67, 0x71, 0x56, 0xec, 0xc6, 0xf7, 0x79, 0xde, 0x6a, 0x2e, 0x00, 0x31, 0x31, 0x59,
+ 0xaa, 0x92, 0xc3, 0x6f, 0x9b, 0x84, 0xee, 0x42, 0xee, 0x74, 0x02, 0x26, 0x91, 0x7d, 0xd8, 0xfc,
+ 0xfa, 0x04, 0x54, 0xf8, 0xd8, 0x12, 0x4d, 0x76, 0x71, 0x10, 0x92, 0xe0, 0x81, 0xad, 0x93, 0xa2,
+ 0x89, 0x4e, 0x42, 0x65, 0xd7, 0x0c, 0xdb, 0x01, 0xde, 0xe2, 0xd3, 0x74, 0x62, 0xd7, 0x0c, 0x75,
+ 0xbc, 0x45, 0x0e, 0x31, 0xb1, 0x1f, 0xd9, 0x5d, 0xdc, 0xee, 0x86, 0x4c, 0x47, 0x76, 0x88, 0xd9,
+ 0xa0, 0xc0, 0x7b, 0xeb, 0x7a, 0x95, 0x7d, 0xbe, 0x17, 0xa2, 0x8f, 0x81, 0x1a, 0x87, 0x38, 0x68,
+ 0x9b, 0x7e, 0xdc, 0x16, 0x14, 0x40, 0x29, 0x66, 0x0f, 0x0f, 0xe6, 0xa7, 0x36, 0x42, 0x1c, 0x2c,
+ 0xb7, 0x36, 0x1e, 0x32, 0xb2, 0x29, 0x82, 0xba, 0xec, 0xc7, 0x0f, 0x19, 0xed, 0x27, 0x01, 0x85,
+ 0x74, 0x34, 0x32, 0xd4, 0x75, 0x4a, 0x4d, 0xcb, 0x67, 0xd9, 0x58, 0xa5, 0xf4, 0x33, 0x0c, 0x3d,
+ 0xe5, 0x70, 0x06, 0x20, 0x8c, 0x0c, 0x1a, 0x7b, 0x19, 0x51, 0x63, 0x92, 0xda, 0xa2, 0xc6, 0x21,
+ 0x4b, 0xf4, 0xc1, 0x4c, 0xe0, 0x90, 0x23, 0x7b, 0xdb, 0x8c, 0x83, 0xc6, 0x14, 0x2d, 0x9a, 0xae,
+ 0x31, 0xc8, 0x72, 0x4c, 0xb7, 0x07, 0x37, 0xee, 0xb6, 0x3b, 0x5e, 0xe0, 0xc5, 0x91, 0xed, 0xe2,
+ 0xc6, 0x34, 0x65, 0x30, 0xe9, 0xc6, 0xdd, 0xdb, 0x02, 0x46, 0x86, 0xc4, 0xf5, 0xb6, 0x6c, 0x07,
+ 0x37, 0x66, 0xd8, 0x90, 0xb0, 0x16, 0x7a, 0x09, 0x8e, 0x45, 0x9e, 0xd7, 0xee, 0x1a, 0xee, 0x7e,
+ 0xdb, 0xf3, 0xb1, 0xdb, 0x26, 0xd0, 0xb0, 0xa1, 0xd2, 0xad, 0x43, 0x8d, 0x3c, 0xef, 0x9e, 0xe1,
+ 0xee, 0x3f, 0xf0, 0xb1, 0x7b, 0x8b, 0xc0, 0xd1, 0x79, 0xa8, 0x10, 0x59, 0xa6, 0x1f, 0x37, 0x66,
+ 0x69, 0x07, 0x69, 0x02, 0xe4, 0x7e, 0x4c, 0x7a, 0xa7, 0x4f, 0xb8, 0x31, 0xe9, 0x14, 0xd1, 0xb7,
+ 0xe3, 0xb5, 0xc5, 0x68, 0x21, 0x3a, 0x26, 0xb5, 0x8e, 0xf7, 0x29, 0x3e, 0x5e, 0x57, 0x40, 0xf5,
+ 0x7c, 0x1c, 0xd0, 0x42, 0x9f, 0x36, 0x33, 0x45, 0xe3, 0x18, 0x8b, 0x81, 0x13, 0x38, 0x33, 0x19,
+ 0x7a, 0x16, 0x6a, 0xdb, 0x5e, 0x18, 0xb5, 0x5d, 0xa3, 0x8b, 0x1b, 0x73, 0x14, 0xa7, 0x4a, 0x00,
+ 0xf7, 0x8d, 0x2e, 0x26, 0x71, 0x86, 0x11, 0x98, 0xdb, 0x8d, 0xe3, 0x2c, 0xce, 0x20, 0xbf, 0x25,
+ 0x53, 0x75, 0x8d, 0x47, 0x8d, 0x13, 0xb2, 0xa9, 0xee, 0x19, 0x8f, 0x48, 0xf4, 0xe1, 0xdb, 0x56,
+ 0xe3, 0x24, 0x55, 0x9d, 0x4d, 0x79, 0x72, 0xe4, 0xf6, 0x6d, 0x0b, 0x9d, 0x86, 0x31, 0x9f, 0x7c,
+ 0x6b, 0xd0, 0x6f, 0xd5, 0xc3, 0x83, 0xf9, 0xb1, 0x16, 0xf9, 0x48, 0xa1, 0x6c, 0x8e, 0xd8, 0x5e,
+ 0x60, 0x47, 0xfb, 0x8d, 0x53, 0x62, 0x8e, 0xb0, 0x36, 0x0d, 0x69, 0x6c, 0xab, 0xd1, 0x4c, 0x99,
+ 0x6e, 0x10, 0xa6, 0xb1, 0x6d, 0xa1, 0x79, 0xa8, 0xef, 0x79, 0xc1, 0x0e, 0xe9, 0xa8, 0x65, 0x07,
+ 0x8d, 0x67, 0x59, 0xbc, 0xc0, 0x41, 0x2b, 0x36, 0xdd, 0xb5, 0xb9, 0xef, 0x10, 0x9f, 0xa2, 0xdd,
+ 0x3c, 0x4d, 0x91, 0xa6, 0x19, 0x78, 0x83, 0x43, 0xb5, 0x5f, 0x8f, 0x43, 0x95, 0x4c, 0x8a, 0xde,
+ 0x9d, 0x74, 0x49, 0xac, 0x9a, 0x1f, 0x85, 0x71, 0x31, 0x95, 0xca, 0x85, 0x97, 0x22, 0x82, 0x03,
+ 0xfd, 0xa1, 0x33, 0x82, 0xe6, 0x0f, 0x4b, 0x30, 0x46, 0xda, 0xd2, 0x3b, 0x8c, 0x5a, 0xe6, 0x1d,
+ 0xc6, 0x0d, 0x98, 0x20, 0x6e, 0x84, 0x59, 0x22, 0xa2, 0x68, 0x41, 0x4d, 0x78, 0xeb, 0x04, 0x57,
+ 0xe7, 0x24, 0xc4, 0xf1, 0xe8, 0x89, 0x58, 0x84, 0xbf, 0xbc, 0x85, 0x96, 0xa0, 0xba, 0x85, 0x8d,
+ 0x28, 0x0e, 0x30, 0x5b, 0x15, 0xa7, 0x8b, 0x9e, 0xb0, 0x08, 0xb6, 0xb7, 0x18, 0xb6, 0x9e, 0x90,
+ 0x11, 0xeb, 0x76, 0x6d, 0xb7, 0xed, 0x18, 0x11, 0x76, 0x4d, 0xf6, 0x06, 0xab, 0xac, 0x43, 0xd7,
+ 0x76, 0xef, 0x32, 0x08, 0x71, 0x1f, 0x3b, 0x6c, 0xd3, 0x0c, 0x2e, 0xe6, 0xe9, 0xf4, 0xaa, 0x1d,
+ 0xd2, 0xfc, 0x31, 0x46, 0x1f, 0x87, 0x9a, 0x65, 0x07, 0xd8, 0xa4, 0xe7, 0x91, 0x4a, 0x9f, 0x44,
+ 0xc9, 0x8a, 0xc0, 0xd2, 0x53, 0x82, 0xe6, 0xcf, 0xc8, 0x76, 0x45, 0x7a, 0x98, 0x15, 0xa2, 0xf4,
+ 0x08, 0x69, 0x40, 0xc5, 0xb0, 0x2c, 0xba, 0xb4, 0xb2, 0xb5, 0x49, 0x34, 0xb3, 0xe2, 0xcb, 0x23,
+ 0x8a, 0x27, 0x7c, 0x45, 0xb7, 0xd9, 0x12, 0x2b, 0x9a, 0xe8, 0x4d, 0xa8, 0x84, 0x51, 0x80, 0x8d,
+ 0xae, 0x48, 0x36, 0x3c, 0xdf, 0xdf, 0xac, 0xeb, 0x14, 0x59, 0x17, 0x44, 0xcd, 0x73, 0x30, 0xc1,
+ 0x40, 0x45, 0xee, 0xa0, 0xbd, 0x0f, 0x15, 0x3e, 0x16, 0x08, 0xc1, 0x34, 0x4f, 0x3b, 0x72, 0x88,
+ 0xfa, 0x0c, 0x9a, 0x81, 0xfa, 0x3b, 0x38, 0xdc, 0x16, 0x00, 0x05, 0x4d, 0x03, 0xdc, 0xbc, 0xbb,
+ 0x2a, 0xda, 0x34, 0x0d, 0x79, 0xd7, 0x33, 0x0d, 0x47, 0x40, 0xca, 0x34, 0x81, 0xe9, 0x05, 0xa2,
+ 0x3d, 0x46, 0x58, 0xbc, 0x1d, 0xdb, 0xa6, 0x00, 0x8c, 0x6b, 0xdf, 0x57, 0xa0, 0xda, 0x12, 0x7b,
+ 0xd2, 0x1c, 0x8c, 0x87, 0x91, 0x11, 0x89, 0xf3, 0x35, 0x6b, 0x10, 0xa8, 0xe5, 0xd9, 0x6e, 0x47,
+ 0x64, 0x3b, 0x68, 0x23, 0xb3, 0xb7, 0x11, 0x23, 0x97, 0xa4, 0xbd, 0xed, 0x34, 0xd4, 0x4c, 0x7e,
+ 0x46, 0x60, 0x1b, 0xd5, 0x98, 0x9e, 0x02, 0xd8, 0x69, 0x3b, 0x32, 0x1c, 0xea, 0x56, 0x63, 0x3a,
+ 0x6b, 0x50, 0x29, 0xd8, 0x31, 0xd8, 0x53, 0xc8, 0x31, 0x9d, 0x35, 0x34, 0x17, 0x66, 0xd9, 0xad,
+ 0xc6, 0x3b, 0x76, 0xb4, 0xcd, 0x52, 0x64, 0xe1, 0x28, 0x6f, 0x71, 0x16, 0xa0, 0xce, 0xd2, 0x69,
+ 0x61, 0xdb, 0xdf, 0xc9, 0xbc, 0x74, 0x12, 0xf9, 0xb6, 0x50, 0x07, 0x8e, 0xd1, 0xda, 0x09, 0xb5,
+ 0x03, 0x05, 0x66, 0x1f, 0xc4, 0xd1, 0x83, 0x2d, 0x9a, 0xdd, 0x14, 0x6f, 0xc7, 0xfa, 0xe4, 0x13,
+ 0x47, 0xc8, 0xcc, 0x4b, 0xcf, 0x73, 0x88, 0xc1, 0x26, 0xd2, 0x37, 0x79, 0xfc, 0xa1, 0xdd, 0x58,
+ 0xfa, 0xd0, 0x6e, 0x0e, 0xc6, 0xb7, 0x1c, 0xa3, 0x13, 0x52, 0x1b, 0x55, 0x74, 0xd6, 0xa0, 0xc9,
+ 0x31, 0xf1, 0xae, 0xad, 0x9d, 0x4d, 0x0d, 0xaa, 0xc9, 0x87, 0x16, 0x7f, 0xbe, 0x98, 0x3c, 0x14,
+ 0xab, 0x48, 0x0f, 0xc5, 0xb4, 0x9f, 0x28, 0x70, 0x2c, 0xa7, 0xb2, 0x0c, 0xad, 0x00, 0xb0, 0xd0,
+ 0x58, 0xba, 0xf5, 0x90, 0x96, 0x8d, 0x38, 0xdc, 0xee, 0xa9, 0x49, 0xa3, 0x41, 0x33, 0x4b, 0x2b,
+ 0x47, 0xe2, 0x27, 0xb1, 0xc6, 0x66, 0xec, 0x5a, 0x0e, 0x4e, 0x4b, 0x53, 0xa9, 0x35, 0x6e, 0x52,
+ 0xe0, 0xda, 0x0a, 0x89, 0x64, 0xe8, 0x2f, 0x2b, 0xcd, 0xb9, 0xf0, 0xdb, 0x62, 0x96, 0x73, 0xb9,
+ 0x0e, 0x73, 0x01, 0x36, 0x6d, 0xdf, 0xc6, 0x6e, 0xd4, 0x96, 0x8e, 0xc2, 0xcc, 0x34, 0x28, 0xf9,
+ 0xd6, 0x12, 0x67, 0x62, 0xed, 0x3e, 0x40, 0x5a, 0xc0, 0xc6, 0x1e, 0xf3, 0x92, 0x5f, 0xf2, 0x0b,
+ 0x58, 0x06, 0x21, 0x07, 0x68, 0x29, 0x8f, 0x44, 0x56, 0x0b, 0xee, 0xd1, 0xe2, 0x90, 0xbe, 0x64,
+ 0x59, 0x81, 0xf6, 0x55, 0x05, 0x4e, 0x11, 0x86, 0x6c, 0x00, 0x79, 0x89, 0xae, 0x38, 0x8b, 0xa1,
+ 0x37, 0xb3, 0x69, 0xbb, 0xe1, 0x2b, 0xf7, 0x78, 0xff, 0x86, 0x77, 0x17, 0x72, 0xa6, 0x68, 0xa6,
+ 0x8a, 0xf0, 0x92, 0xbd, 0x54, 0x93, 0xd7, 0x60, 0x82, 0x57, 0xfb, 0x29, 0xc3, 0x55, 0xfb, 0x71,
+ 0xf4, 0x51, 0x54, 0xf8, 0xfb, 0x52, 0xf2, 0xf6, 0xa3, 0xdf, 0x09, 0x75, 0x94, 0x9a, 0xe2, 0x1b,
+ 0xd0, 0x0c, 0xed, 0x8e, 0x8b, 0x2d, 0x7e, 0x3c, 0x8f, 0xf6, 0xdb, 0x47, 0x32, 0x1e, 0x27, 0x19,
+ 0xc6, 0x1a, 0x47, 0x48, 0xc6, 0x1a, 0x5d, 0x83, 0x63, 0xbb, 0x5c, 0x8f, 0xb6, 0x74, 0xc0, 0x66,
+ 0xe9, 0x10, 0xb4, 0x7b, 0x44, 0x45, 0x32, 0x61, 0x02, 0xaa, 0x26, 0x4b, 0x85, 0xb5, 0x2d, 0xb2,
+ 0xb8, 0xb1, 0x65, 0x5d, 0x95, 0x3f, 0xac, 0x90, 0x75, 0x8e, 0x9e, 0xf3, 0x45, 0xd6, 0x8c, 0xa1,
+ 0xb2, 0x8d, 0x6f, 0x3a, 0x05, 0x53, 0xc4, 0x6c, 0xaa, 0x62, 0xa2, 0x37, 0x55, 0x41, 0x36, 0x66,
+ 0x9e, 0x4e, 0xa8, 0xb0, 0xa8, 0x99, 0xb5, 0xb4, 0x6f, 0x2b, 0x70, 0x9c, 0x0c, 0x08, 0x5b, 0xa7,
+ 0xa8, 0x6b, 0x6d, 0xf8, 0x44, 0xce, 0xe3, 0x0f, 0x66, 0x32, 0x8b, 0x4a, 0xf2, 0x2c, 0x1a, 0xe1,
+ 0xd6, 0xf7, 0xbf, 0x32, 0x0b, 0x1e, 0x77, 0xd7, 0xe6, 0xf9, 0xf4, 0xa8, 0x2a, 0x5d, 0x42, 0x28,
+ 0x99, 0x4b, 0x88, 0xe6, 0x5f, 0x27, 0xe7, 0xca, 0x4f, 0xa6, 0x65, 0x14, 0x4c, 0xff, 0x8b, 0xb9,
+ 0xfa, 0x1f, 0x59, 0x58, 0xd3, 0x57, 0xad, 0x64, 0xc7, 0x70, 0x30, 0x09, 0xcb, 0x1f, 0x89, 0x1b,
+ 0xd3, 0x14, 0x80, 0x2e, 0x83, 0xca, 0xcf, 0xe3, 0xa9, 0xab, 0xb0, 0x65, 0x63, 0x9a, 0x1d, 0xc5,
+ 0x13, 0x0f, 0xb9, 0x02, 0xaa, 0xe1, 0x04, 0xd8, 0xb0, 0xf6, 0xdb, 0x01, 0x7f, 0xc7, 0x42, 0xc7,
+ 0xbb, 0xaa, 0xcf, 0x70, 0xb8, 0x78, 0xde, 0x42, 0xeb, 0x7a, 0x52, 0x8d, 0xd6, 0xb1, 0xe1, 0x34,
+ 0xef, 0xa7, 0xdd, 0xee, 0xb3, 0xe4, 0xe7, 0x69, 0x53, 0xca, 0xd3, 0xa6, 0x79, 0x41, 0x18, 0xe8,
+ 0x34, 0xd4, 0x92, 0xf5, 0x59, 0xac, 0x4a, 0x09, 0x40, 0x7b, 0x03, 0x66, 0x6f, 0xd9, 0x41, 0x18,
+ 0xdd, 0x35, 0xc2, 0x68, 0x99, 0x6d, 0x09, 0x74, 0x2f, 0xde, 0x22, 0x40, 0xfe, 0x7e, 0x9b, 0x35,
+ 0x68, 0x06, 0xd0, 0x08, 0x23, 0xfe, 0xbe, 0x93, 0xfe, 0xd6, 0xfe, 0x49, 0x81, 0x63, 0xfc, 0xa4,
+ 0x2a, 0xd5, 0xb9, 0xb0, 0xb3, 0x0f, 0x36, 0x1c, 0x6c, 0xb5, 0x37, 0xbd, 0x47, 0xc2, 0xa8, 0x0c,
+ 0x72, 0xd3, 0x7b, 0x44, 0xd6, 0xc2, 0xc0, 0xd8, 0x6b, 0x07, 0x1e, 0x2b, 0xf3, 0xe2, 0x06, 0xad,
+ 0x07, 0xc6, 0x9e, 0xce, 0x41, 0xcd, 0x0f, 0x14, 0x28, 0x13, 0x54, 0x29, 0xd6, 0x52, 0xb2, 0xb1,
+ 0xd6, 0x1c, 0x8c, 0xd3, 0x77, 0xfe, 0xc2, 0xff, 0x68, 0x63, 0x04, 0xff, 0xeb, 0x2d, 0x6c, 0x9f,
+ 0xcc, 0xbd, 0xf7, 0xfd, 0xb5, 0x02, 0xc7, 0x75, 0xbc, 0x15, 0xe0, 0x70, 0x3b, 0x5b, 0xf4, 0xd9,
+ 0x7c, 0x75, 0x40, 0x80, 0x3d, 0x07, 0xe3, 0xec, 0xea, 0xba, 0xc4, 0xd2, 0x03, 0xec, 0xe6, 0xfa,
+ 0xed, 0xc7, 0xac, 0xbe, 0x24, 0x86, 0x20, 0xa7, 0x50, 0x2f, 0x8e, 0xc4, 0xa1, 0x9d, 0x37, 0x9b,
+ 0xef, 0x8a, 0xa1, 0x6e, 0x41, 0x9d, 0x06, 0xff, 0xed, 0x2d, 0x2f, 0x76, 0x2d, 0x7e, 0x66, 0xb8,
+ 0x96, 0x3b, 0x1f, 0x72, 0xbb, 0xc4, 0x0e, 0x10, 0x40, 0x79, 0xdc, 0x22, 0x2c, 0xae, 0xda, 0x90,
+ 0xde, 0xe1, 0xa2, 0x13, 0xbc, 0x04, 0x8c, 0xdd, 0x7f, 0x5b, 0x78, 0xcb, 0x76, 0xb1, 0xa5, 0x3e,
+ 0x83, 0xe6, 0x78, 0xd5, 0x0e, 0x81, 0xf3, 0x25, 0x5b, 0x55, 0x32, 0x50, 0x2e, 0x86, 0x5d, 0x7e,
+ 0x27, 0x50, 0xa9, 0xee, 0x4f, 0x2d, 0x5f, 0xfd, 0x4a, 0x0d, 0x6a, 0xe9, 0x55, 0xe5, 0x09, 0x40,
+ 0x49, 0x43, 0x96, 0x75, 0x1e, 0xe6, 0x13, 0x38, 0x2f, 0x15, 0x4a, 0x5f, 0x4a, 0xd3, 0xe7, 0x35,
+ 0xaa, 0x82, 0x2e, 0xc0, 0x73, 0x59, 0xa4, 0xec, 0xbb, 0x63, 0x86, 0x56, 0x42, 0xf3, 0xf0, 0x6c,
+ 0x82, 0x76, 0xf4, 0x61, 0xa7, 0x8a, 0xd1, 0x19, 0x38, 0x95, 0x8b, 0x70, 0x17, 0x6f, 0x45, 0xea,
+ 0x16, 0xba, 0x0a, 0x17, 0x7b, 0x3f, 0xe7, 0x3f, 0x9f, 0x54, 0x3b, 0xe8, 0x0a, 0x5c, 0xe8, 0x8f,
+ 0x2b, 0xca, 0xdb, 0xb7, 0xd1, 0x75, 0x78, 0xb1, 0x3f, 0x6a, 0xf6, 0xf5, 0xa3, 0x6a, 0xa3, 0x45,
+ 0x58, 0xe8, 0x4f, 0xf1, 0x20, 0x8e, 0x3a, 0x24, 0x72, 0x16, 0xcf, 0x15, 0xd5, 0xcf, 0xa1, 0x05,
+ 0xb8, 0x3a, 0x1c, 0xcd, 0x3a, 0x76, 0x23, 0x75, 0x67, 0xb0, 0x8c, 0x35, 0xd7, 0xf4, 0xba, 0xb6,
+ 0xdb, 0x11, 0x8b, 0x9c, 0xea, 0xa0, 0x57, 0xe0, 0xda, 0x70, 0x34, 0xc9, 0xd3, 0x38, 0xb5, 0x3b,
+ 0xbc, 0x20, 0xf1, 0xa6, 0x4d, 0x75, 0x91, 0x06, 0x67, 0x0b, 0x68, 0xf8, 0xeb, 0x32, 0xd5, 0x43,
+ 0xcf, 0xc3, 0xb9, 0x02, 0x9c, 0xe4, 0x3d, 0x98, 0xea, 0x23, 0x0d, 0xce, 0x24, 0x58, 0x3d, 0x35,
+ 0xce, 0xcc, 0x6d, 0x7e, 0xac, 0xa0, 0xeb, 0xf0, 0x42, 0x82, 0xd3, 0xb7, 0x56, 0x97, 0x51, 0xfc,
+ 0xa0, 0x84, 0x5e, 0x95, 0x0c, 0x71, 0xb4, 0xda, 0x55, 0x7a, 0x57, 0xbd, 0xe4, 0xba, 0x5e, 0xec,
+ 0x9a, 0xd8, 0x52, 0xff, 0xbc, 0x84, 0x16, 0xe0, 0x4a, 0xb1, 0x9c, 0x4c, 0xb5, 0x2e, 0xb6, 0xd4,
+ 0xbf, 0x28, 0xa1, 0x8b, 0x92, 0xdb, 0x17, 0x3d, 0x3e, 0x53, 0xbf, 0x5d, 0x46, 0x97, 0xe1, 0x7c,
+ 0x3f, 0x3c, 0xfe, 0x2a, 0x4c, 0xfd, 0x4e, 0x19, 0x9d, 0x95, 0x26, 0x40, 0xef, 0x6b, 0x2e, 0xf5,
+ 0xbb, 0x65, 0x74, 0x5e, 0xb2, 0x7b, 0x6e, 0x74, 0xa1, 0xfe, 0x7e, 0x19, 0x5d, 0x02, 0x2d, 0x83,
+ 0x94, 0x1b, 0xdd, 0xaa, 0xdf, 0xcb, 0xea, 0x55, 0x1c, 0x7d, 0xaa, 0x7f, 0x50, 0x46, 0x2f, 0x1f,
+ 0x9d, 0x22, 0xfd, 0x82, 0x44, 0xf5, 0x97, 0xe5, 0x8c, 0x71, 0x32, 0xc5, 0x95, 0xfc, 0xcc, 0x42,
+ 0xdd, 0xfc, 0x5f, 0x2a, 0x57, 0xbf, 0x21, 0x6e, 0xd1, 0x73, 0x8a, 0x3f, 0xc8, 0xc2, 0x52, 0xf4,
+ 0xad, 0x67, 0x91, 0x2a, 0x42, 0xe3, 0xbb, 0xa4, 0xaa, 0x10, 0x7f, 0x2c, 0x46, 0x62, 0xaa, 0xa9,
+ 0xa5, 0xab, 0x7f, 0xa3, 0x24, 0x2f, 0x02, 0xd8, 0xb3, 0x98, 0x53, 0xc9, 0xe3, 0x03, 0xda, 0x96,
+ 0xc5, 0xf6, 0x7c, 0x7a, 0xe8, 0xf1, 0x09, 0xa3, 0x2a, 0x64, 0xd9, 0x95, 0x3f, 0x25, 0x73, 0xb4,
+ 0x84, 0x8e, 0xc3, 0xac, 0xfc, 0x85, 0x39, 0x49, 0x19, 0x9d, 0x4c, 0x4a, 0xfc, 0x39, 0x01, 0xf3,
+ 0x89, 0xb1, 0x5e, 0x21, 0xe9, 0xcc, 0x1d, 0xef, 0xa5, 0x11, 0x53, 0x6f, 0xe2, 0xea, 0x6d, 0xa8,
+ 0x25, 0xf9, 0x0e, 0x34, 0x0d, 0xc0, 0xb3, 0x0b, 0x2b, 0x76, 0xa0, 0x3e, 0x43, 0xda, 0x6b, 0xee,
+ 0x26, 0xd9, 0x6d, 0x48, 0x5b, 0x41, 0x33, 0x50, 0x7f, 0x10, 0x47, 0x09, 0xa0, 0x84, 0x6a, 0x30,
+ 0x7e, 0xd3, 0x26, 0x3f, 0xcb, 0x8b, 0xdf, 0xbc, 0x02, 0x33, 0xe2, 0xbf, 0x9f, 0x88, 0xfb, 0xf9,
+ 0x30, 0xe7, 0xd1, 0x1e, 0x5a, 0xe8, 0x77, 0x91, 0x94, 0xe2, 0x2d, 0x24, 0x2f, 0xfb, 0x86, 0xc6,
+ 0xf7, 0x9d, 0xfd, 0xeb, 0x0a, 0xfa, 0xb2, 0x52, 0xf8, 0xb6, 0x0f, 0xbd, 0x3a, 0xd2, 0xb3, 0x2d,
+ 0xa1, 0xc1, 0xe2, 0x88, 0x54, 0x64, 0xbf, 0x27, 0x5a, 0x14, 0x6c, 0x0d, 0x05, 0x5a, 0x14, 0x60,
+ 0x0f, 0xd0, 0xa2, 0x98, 0x8a, 0x68, 0xf1, 0x85, 0x82, 0x07, 0x4f, 0x68, 0x18, 0x66, 0x1c, 0x37,
+ 0x51, 0xe0, 0xfa, 0x48, 0x34, 0x44, 0xfc, 0xe7, 0xf3, 0x9f, 0x50, 0xa1, 0x97, 0x87, 0xe0, 0xc4,
+ 0x50, 0x13, 0xe1, 0xd7, 0x46, 0x21, 0x21, 0xb2, 0xbf, 0xa3, 0xf4, 0x7f, 0x5d, 0x85, 0x5e, 0x1f,
+ 0xca, 0x9e, 0x32, 0x49, 0xa2, 0xcc, 0x6b, 0x8f, 0x43, 0x4a, 0x94, 0x8a, 0xf2, 0x9e, 0x61, 0xa1,
+ 0x61, 0xfa, 0x46, 0x10, 0x13, 0xf9, 0x2f, 0x0d, 0x4f, 0x90, 0x3b, 0x0c, 0x6c, 0x7b, 0x1e, 0x6a,
+ 0x18, 0x18, 0xea, 0x48, 0xc3, 0x90, 0x90, 0x14, 0x79, 0x20, 0x59, 0x95, 0x86, 0xf5, 0x40, 0x82,
+ 0x3b, 0xaa, 0x07, 0x72, 0x1a, 0x22, 0x7e, 0x33, 0xfb, 0x68, 0x0b, 0x5d, 0xe9, 0xc7, 0x81, 0xa2,
+ 0x24, 0xc2, 0x2e, 0x0d, 0x83, 0x4a, 0x64, 0x6c, 0xf7, 0x3e, 0xe3, 0x42, 0x2f, 0xf4, 0x23, 0xe5,
+ 0x48, 0x89, 0x9c, 0x2b, 0xc3, 0x21, 0x13, 0x49, 0x7b, 0xb9, 0x8f, 0xbb, 0x50, 0x5f, 0xb3, 0xc8,
+ 0x98, 0x89, 0xcc, 0x85, 0x11, 0x28, 0x88, 0xe0, 0x2f, 0x2a, 0x45, 0x6f, 0xc0, 0xd0, 0x2b, 0xf9,
+ 0x2f, 0x2b, 0x72, 0x91, 0x13, 0xf9, 0x2f, 0x8f, 0x46, 0xc4, 0x9d, 0x38, 0xef, 0xbd, 0x18, 0x1a,
+ 0x8e, 0x15, 0x41, 0x1d, 0xe0, 0xc4, 0x05, 0x24, 0xdc, 0x89, 0x73, 0x5f, 0x93, 0x15, 0x38, 0x71,
+ 0x2e, 0xee, 0x00, 0x27, 0x2e, 0xa2, 0x21, 0xe2, 0x7f, 0xa0, 0x0c, 0xf9, 0xf0, 0x0c, 0xdd, 0x1c,
+ 0x8a, 0x77, 0x2e, 0x6d, 0xa2, 0xdf, 0x27, 0x9f, 0x88, 0x07, 0xd1, 0xf7, 0x0f, 0x07, 0x3e, 0x61,
+ 0x43, 0x37, 0x86, 0x13, 0x92, 0x21, 0x4a, 0x34, 0x7c, 0xfd, 0xf1, 0x88, 0x89, 0x6a, 0x7f, 0x3c,
+ 0xc4, 0x9b, 0x36, 0xf4, 0xc6, 0x50, 0xfc, 0x7b, 0xc9, 0x12, 0xf5, 0x6e, 0x3c, 0x2e, 0x39, 0x51,
+ 0x70, 0xe7, 0xc8, 0x03, 0x37, 0x94, 0x1f, 0x00, 0xf5, 0x60, 0x25, 0xd2, 0xaf, 0x0e, 0x89, 0xcd,
+ 0x57, 0xae, 0xec, 0x13, 0xb6, 0x82, 0x95, 0x2b, 0x8b, 0x34, 0x60, 0xe5, 0x3a, 0x82, 0x4c, 0x24,
+ 0xb9, 0x39, 0xcf, 0xa6, 0x0a, 0x22, 0xc1, 0x23, 0x78, 0x03, 0x56, 0xe4, 0xa3, 0x4f, 0xdf, 0xae,
+ 0x2b, 0x68, 0xe7, 0xe8, 0x6b, 0x25, 0xf4, 0x52, 0x3f, 0xf2, 0x04, 0x2d, 0x91, 0x76, 0x71, 0x20,
+ 0xba, 0x10, 0xf6, 0xae, 0xf4, 0x44, 0x08, 0xf5, 0x21, 0xa3, 0xc5, 0x23, 0x82, 0xfd, 0xf3, 0x03,
+ 0xf1, 0x88, 0xdd, 0x70, 0xcf, 0xeb, 0x1b, 0x54, 0x30, 0xbc, 0x32, 0x4e, 0x22, 0xe2, 0xf2, 0x50,
+ 0xb8, 0xdc, 0xeb, 0x7a, 0x1e, 0xde, 0x14, 0x78, 0x5d, 0x0f, 0xd6, 0x00, 0xaf, 0x3b, 0x8a, 0x4d,
+ 0x84, 0x85, 0x39, 0xaf, 0x72, 0xfa, 0xf9, 0x42, 0xe6, 0x2d, 0x4a, 0xff, 0x53, 0x41, 0x1e, 0x3e,
+ 0x3b, 0x15, 0x74, 0x8f, 0xbc, 0xbb, 0x28, 0xec, 0x61, 0x06, 0x6b, 0x60, 0x0f, 0x7b, 0xb1, 0x99,
+ 0xb8, 0x2f, 0x29, 0x45, 0x4f, 0x23, 0x0a, 0x36, 0xcc, 0x7c, 0xe4, 0x01, 0x1b, 0x66, 0x21, 0x11,
+ 0x53, 0xe2, 0x3d, 0xf9, 0x39, 0x00, 0xba, 0x54, 0xcc, 0x22, 0x3b, 0x96, 0x17, 0x06, 0x23, 0x92,
+ 0x61, 0xfc, 0x6a, 0x9f, 0x9a, 0x76, 0xf4, 0xff, 0x8a, 0x79, 0xe4, 0xa0, 0x27, 0xa2, 0x5f, 0x19,
+ 0x95, 0x8c, 0x28, 0xf2, 0x9e, 0x5c, 0xe1, 0x86, 0x06, 0x16, 0x8e, 0xf5, 0xef, 0x66, 0x06, 0x91,
+ 0xc7, 0x5c, 0x39, 0x95, 0xc9, 0x05, 0x31, 0x57, 0x0e, 0xe6, 0x80, 0x98, 0x2b, 0x9f, 0x42, 0x9c,
+ 0x20, 0x0b, 0xea, 0xb3, 0x0b, 0x4e, 0x90, 0x05, 0xd8, 0x03, 0x4e, 0x90, 0xc5, 0x54, 0x22, 0xf6,
+ 0x18, 0xaa, 0xc0, 0xb9, 0x20, 0xf6, 0x18, 0x8a, 0x76, 0x40, 0xec, 0x31, 0x2c, 0x0f, 0xa2, 0xef,
+ 0x5f, 0x8d, 0x52, 0xa5, 0x8c, 0x6e, 0x8d, 0x2e, 0x2f, 0xd7, 0xb2, 0x2b, 0x4f, 0xcc, 0x87, 0xe8,
+ 0xfe, 0x81, 0x52, 0x58, 0xcb, 0x5c, 0x30, 0xe2, 0x05, 0xd8, 0x03, 0x46, 0xbc, 0x98, 0x8a, 0xad,
+ 0x1b, 0x61, 0x4e, 0x31, 0x71, 0xff, 0xb4, 0x4d, 0x8a, 0x37, 0x5c, 0xda, 0x26, 0x83, 0xcf, 0x84,
+ 0xfe, 0xd1, 0xe0, 0x9a, 0x5d, 0xf4, 0xf1, 0x82, 0xfb, 0x92, 0xbe, 0x54, 0x89, 0x46, 0x1f, 0x7b,
+ 0x4c, 0x6a, 0x32, 0x34, 0x9f, 0x4a, 0x8b, 0xc1, 0xd0, 0x80, 0xb2, 0x29, 0x21, 0x6e, 0x50, 0xd1,
+ 0x16, 0xe5, 0xfb, 0x7e, 0xce, 0x35, 0x6b, 0x81, 0xa9, 0x8f, 0xe0, 0x0d, 0x30, 0x75, 0x1e, 0x3e,
+ 0x0f, 0xfa, 0xb2, 0xf7, 0x9b, 0x05, 0x41, 0x5f, 0x16, 0x69, 0x40, 0xd0, 0x77, 0x04, 0x99, 0x1f,
+ 0x9b, 0x72, 0xef, 0xb2, 0x0a, 0x8e, 0x4d, 0xf9, 0xf7, 0x5e, 0xfd, 0x8f, 0x4d, 0x45, 0x34, 0xbe,
+ 0xb3, 0x7f, 0xf3, 0x23, 0x3f, 0xfd, 0xe7, 0xb3, 0xcf, 0xfc, 0xed, 0xe1, 0x59, 0xe5, 0xa7, 0x87,
+ 0x67, 0x95, 0x9f, 0x1f, 0x9e, 0x55, 0x3e, 0xf3, 0xfc, 0x26, 0x0e, 0xa2, 0xfd, 0x85, 0x08, 0x9b,
+ 0xdb, 0xd7, 0x38, 0xb7, 0x6b, 0xfe, 0x4e, 0xe7, 0x5a, 0xe6, 0xdf, 0xea, 0x6f, 0x4e, 0xd0, 0xe6,
+ 0x2b, 0xff, 0x13, 0x00, 0x00, 0xff, 0xff, 0x81, 0x08, 0x42, 0xbc, 0x6e, 0x5f, 0x00, 0x00,
}
func (m *Account) Marshal() (dAtA []byte, err error) {
@@ -12423,7 +12006,7 @@ func (m *GroupAddMemberDevice) MarshalToSizedBuffer(dAtA []byte) (int, error) {
return len(dAtA) - i, nil
}
-func (m *DeviceSecret) Marshal() (dAtA []byte, err error) {
+func (m *DeviceChainKey) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
@@ -12433,12 +12016,12 @@ func (m *DeviceSecret) Marshal() (dAtA []byte, err error) {
return dAtA[:n], nil
}
-func (m *DeviceSecret) MarshalTo(dAtA []byte) (int, error) {
+func (m *DeviceChainKey) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
-func (m *DeviceSecret) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+func (m *DeviceChainKey) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
@@ -12462,7 +12045,7 @@ func (m *DeviceSecret) MarshalToSizedBuffer(dAtA []byte) (int, error) {
return len(dAtA) - i, nil
}
-func (m *GroupAddDeviceSecret) Marshal() (dAtA []byte, err error) {
+func (m *GroupAddDeviceChainKey) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
@@ -12472,12 +12055,12 @@ func (m *GroupAddDeviceSecret) Marshal() (dAtA []byte, err error) {
return dAtA[:n], nil
}
-func (m *GroupAddDeviceSecret) MarshalTo(dAtA []byte) (int, error) {
+func (m *GroupAddDeviceChainKey) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
-func (m *GroupAddDeviceSecret) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+func (m *GroupAddDeviceChainKey) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
@@ -18889,7 +18472,7 @@ func (m *PushMemberTokenUpdate) MarshalToSizedBuffer(dAtA []byte) (int, error) {
return len(dAtA) - i, nil
}
-func (m *PushReceive) Marshal() (dAtA []byte, err error) {
+func (m *OutOfStoreReceive) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
@@ -18899,12 +18482,12 @@ func (m *PushReceive) Marshal() (dAtA []byte, err error) {
return dAtA[:n], nil
}
-func (m *PushReceive) MarshalTo(dAtA []byte) (int, error) {
+func (m *OutOfStoreReceive) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
-func (m *PushReceive) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+func (m *OutOfStoreReceive) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
@@ -18916,7 +18499,7 @@ func (m *PushReceive) MarshalToSizedBuffer(dAtA []byte) (int, error) {
return len(dAtA) - i, nil
}
-func (m *PushReceive_Request) Marshal() (dAtA []byte, err error) {
+func (m *OutOfStoreReceive_Request) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
@@ -18926,12 +18509,12 @@ func (m *PushReceive_Request) Marshal() (dAtA []byte, err error) {
return dAtA[:n], nil
}
-func (m *PushReceive_Request) MarshalTo(dAtA []byte) (int, error) {
+func (m *OutOfStoreReceive_Request) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
-func (m *PushReceive_Request) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+func (m *OutOfStoreReceive_Request) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
@@ -18950,7 +18533,7 @@ func (m *PushReceive_Request) MarshalToSizedBuffer(dAtA []byte) (int, error) {
return len(dAtA) - i, nil
}
-func (m *PushReceive_Reply) Marshal() (dAtA []byte, err error) {
+func (m *OutOfStoreReceive_Reply) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
@@ -18960,12 +18543,12 @@ func (m *PushReceive_Reply) Marshal() (dAtA []byte, err error) {
return dAtA[:n], nil
}
-func (m *PushReceive_Reply) MarshalTo(dAtA []byte) (int, error) {
+func (m *OutOfStoreReceive_Reply) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
-func (m *PushReceive_Reply) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+func (m *OutOfStoreReceive_Reply) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
@@ -19013,7 +18596,7 @@ func (m *PushReceive_Reply) MarshalToSizedBuffer(dAtA []byte) (int, error) {
return len(dAtA) - i, nil
}
-func (m *PushSend) Marshal() (dAtA []byte, err error) {
+func (m *OutOfStoreSeal) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
@@ -19023,12 +18606,12 @@ func (m *PushSend) Marshal() (dAtA []byte, err error) {
return dAtA[:n], nil
}
-func (m *PushSend) MarshalTo(dAtA []byte) (int, error) {
+func (m *OutOfStoreSeal) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
-func (m *PushSend) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+func (m *OutOfStoreSeal) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
@@ -19040,7 +18623,7 @@ func (m *PushSend) MarshalToSizedBuffer(dAtA []byte) (int, error) {
return len(dAtA) - i, nil
}
-func (m *PushSend_Request) Marshal() (dAtA []byte, err error) {
+func (m *OutOfStoreSeal_Request) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
@@ -19050,12 +18633,12 @@ func (m *PushSend_Request) Marshal() (dAtA []byte, err error) {
return dAtA[:n], nil
}
-func (m *PushSend_Request) MarshalTo(dAtA []byte) (int, error) {
+func (m *OutOfStoreSeal_Request) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
-func (m *PushSend_Request) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+func (m *OutOfStoreSeal_Request) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
@@ -19064,20 +18647,6 @@ func (m *PushSend_Request) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i -= len(m.XXX_unrecognized)
copy(dAtA[i:], m.XXX_unrecognized)
}
- if len(m.GroupMembers) > 0 {
- for iNdEx := len(m.GroupMembers) - 1; iNdEx >= 0; iNdEx-- {
- {
- size, err := m.GroupMembers[iNdEx].MarshalToSizedBuffer(dAtA[:i])
- if err != nil {
- return 0, err
- }
- i -= size
- i = encodeVarintProtocoltypes(dAtA, i, uint64(size))
- }
- i--
- dAtA[i] = 0x1a
- }
- }
if len(m.GroupPublicKey) > 0 {
i -= len(m.GroupPublicKey)
copy(dAtA[i:], m.GroupPublicKey)
@@ -19095,7 +18664,7 @@ func (m *PushSend_Request) MarshalToSizedBuffer(dAtA []byte) (int, error) {
return len(dAtA) - i, nil
}
-func (m *PushSend_Reply) Marshal() (dAtA []byte, err error) {
+func (m *OutOfStoreSeal_Reply) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
@@ -19105,12 +18674,12 @@ func (m *PushSend_Reply) Marshal() (dAtA []byte, err error) {
return dAtA[:n], nil
}
-func (m *PushSend_Reply) MarshalTo(dAtA []byte) (int, error) {
+func (m *OutOfStoreSeal_Reply) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
-func (m *PushSend_Reply) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+func (m *OutOfStoreSeal_Reply) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
@@ -19119,321 +18688,16 @@ func (m *PushSend_Reply) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i -= len(m.XXX_unrecognized)
copy(dAtA[i:], m.XXX_unrecognized)
}
- if len(m.GroupMembers) > 0 {
- for iNdEx := len(m.GroupMembers) - 1; iNdEx >= 0; iNdEx-- {
- {
- size, err := m.GroupMembers[iNdEx].MarshalToSizedBuffer(dAtA[:i])
- if err != nil {
- return 0, err
- }
- i -= size
- i = encodeVarintProtocoltypes(dAtA, i, uint64(size))
- }
- i--
- dAtA[i] = 0xa
- }
- }
- return len(dAtA) - i, nil
-}
-
-func (m *PushShareToken) Marshal() (dAtA []byte, err error) {
- size := m.Size()
- dAtA = make([]byte, size)
- n, err := m.MarshalToSizedBuffer(dAtA[:size])
- if err != nil {
- return nil, err
- }
- return dAtA[:n], nil
-}
-
-func (m *PushShareToken) MarshalTo(dAtA []byte) (int, error) {
- size := m.Size()
- return m.MarshalToSizedBuffer(dAtA[:size])
-}
-
-func (m *PushShareToken) MarshalToSizedBuffer(dAtA []byte) (int, error) {
- i := len(dAtA)
- _ = i
- var l int
- _ = l
- if m.XXX_unrecognized != nil {
- i -= len(m.XXX_unrecognized)
- copy(dAtA[i:], m.XXX_unrecognized)
- }
- return len(dAtA) - i, nil
-}
-
-func (m *PushShareToken_Request) Marshal() (dAtA []byte, err error) {
- size := m.Size()
- dAtA = make([]byte, size)
- n, err := m.MarshalToSizedBuffer(dAtA[:size])
- if err != nil {
- return nil, err
- }
- return dAtA[:n], nil
-}
-
-func (m *PushShareToken_Request) MarshalTo(dAtA []byte) (int, error) {
- size := m.Size()
- return m.MarshalToSizedBuffer(dAtA[:size])
-}
-
-func (m *PushShareToken_Request) MarshalToSizedBuffer(dAtA []byte) (int, error) {
- i := len(dAtA)
- _ = i
- var l int
- _ = l
- if m.XXX_unrecognized != nil {
- i -= len(m.XXX_unrecognized)
- copy(dAtA[i:], m.XXX_unrecognized)
- }
- if m.Receiver != nil {
- {
- size, err := m.Receiver.MarshalToSizedBuffer(dAtA[:i])
- if err != nil {
- return 0, err
- }
- i -= size
- i = encodeVarintProtocoltypes(dAtA, i, uint64(size))
- }
- i--
- dAtA[i] = 0x1a
- }
- if m.Server != nil {
- {
- size, err := m.Server.MarshalToSizedBuffer(dAtA[:i])
- if err != nil {
- return 0, err
- }
- i -= size
- i = encodeVarintProtocoltypes(dAtA, i, uint64(size))
- }
- i--
- dAtA[i] = 0x12
- }
- if len(m.GroupPK) > 0 {
- i -= len(m.GroupPK)
- copy(dAtA[i:], m.GroupPK)
- i = encodeVarintProtocoltypes(dAtA, i, uint64(len(m.GroupPK)))
+ if len(m.Encrypted) > 0 {
+ i -= len(m.Encrypted)
+ copy(dAtA[i:], m.Encrypted)
+ i = encodeVarintProtocoltypes(dAtA, i, uint64(len(m.Encrypted)))
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
-func (m *PushShareToken_Reply) Marshal() (dAtA []byte, err error) {
- size := m.Size()
- dAtA = make([]byte, size)
- n, err := m.MarshalToSizedBuffer(dAtA[:size])
- if err != nil {
- return nil, err
- }
- return dAtA[:n], nil
-}
-
-func (m *PushShareToken_Reply) MarshalTo(dAtA []byte) (int, error) {
- size := m.Size()
- return m.MarshalToSizedBuffer(dAtA[:size])
-}
-
-func (m *PushShareToken_Reply) MarshalToSizedBuffer(dAtA []byte) (int, error) {
- i := len(dAtA)
- _ = i
- var l int
- _ = l
- if m.XXX_unrecognized != nil {
- i -= len(m.XXX_unrecognized)
- copy(dAtA[i:], m.XXX_unrecognized)
- }
- return len(dAtA) - i, nil
-}
-
-func (m *PushSetDeviceToken) Marshal() (dAtA []byte, err error) {
- size := m.Size()
- dAtA = make([]byte, size)
- n, err := m.MarshalToSizedBuffer(dAtA[:size])
- if err != nil {
- return nil, err
- }
- return dAtA[:n], nil
-}
-
-func (m *PushSetDeviceToken) MarshalTo(dAtA []byte) (int, error) {
- size := m.Size()
- return m.MarshalToSizedBuffer(dAtA[:size])
-}
-
-func (m *PushSetDeviceToken) MarshalToSizedBuffer(dAtA []byte) (int, error) {
- i := len(dAtA)
- _ = i
- var l int
- _ = l
- if m.XXX_unrecognized != nil {
- i -= len(m.XXX_unrecognized)
- copy(dAtA[i:], m.XXX_unrecognized)
- }
- return len(dAtA) - i, nil
-}
-
-func (m *PushSetDeviceToken_Request) Marshal() (dAtA []byte, err error) {
- size := m.Size()
- dAtA = make([]byte, size)
- n, err := m.MarshalToSizedBuffer(dAtA[:size])
- if err != nil {
- return nil, err
- }
- return dAtA[:n], nil
-}
-
-func (m *PushSetDeviceToken_Request) MarshalTo(dAtA []byte) (int, error) {
- size := m.Size()
- return m.MarshalToSizedBuffer(dAtA[:size])
-}
-
-func (m *PushSetDeviceToken_Request) MarshalToSizedBuffer(dAtA []byte) (int, error) {
- i := len(dAtA)
- _ = i
- var l int
- _ = l
- if m.XXX_unrecognized != nil {
- i -= len(m.XXX_unrecognized)
- copy(dAtA[i:], m.XXX_unrecognized)
- }
- if m.Receiver != nil {
- {
- size, err := m.Receiver.MarshalToSizedBuffer(dAtA[:i])
- if err != nil {
- return 0, err
- }
- i -= size
- i = encodeVarintProtocoltypes(dAtA, i, uint64(size))
- }
- i--
- dAtA[i] = 0xa
- }
- return len(dAtA) - i, nil
-}
-
-func (m *PushSetDeviceToken_Reply) Marshal() (dAtA []byte, err error) {
- size := m.Size()
- dAtA = make([]byte, size)
- n, err := m.MarshalToSizedBuffer(dAtA[:size])
- if err != nil {
- return nil, err
- }
- return dAtA[:n], nil
-}
-
-func (m *PushSetDeviceToken_Reply) MarshalTo(dAtA []byte) (int, error) {
- size := m.Size()
- return m.MarshalToSizedBuffer(dAtA[:size])
-}
-
-func (m *PushSetDeviceToken_Reply) MarshalToSizedBuffer(dAtA []byte) (int, error) {
- i := len(dAtA)
- _ = i
- var l int
- _ = l
- if m.XXX_unrecognized != nil {
- i -= len(m.XXX_unrecognized)
- copy(dAtA[i:], m.XXX_unrecognized)
- }
- return len(dAtA) - i, nil
-}
-
-func (m *PushSetServer) Marshal() (dAtA []byte, err error) {
- size := m.Size()
- dAtA = make([]byte, size)
- n, err := m.MarshalToSizedBuffer(dAtA[:size])
- if err != nil {
- return nil, err
- }
- return dAtA[:n], nil
-}
-
-func (m *PushSetServer) MarshalTo(dAtA []byte) (int, error) {
- size := m.Size()
- return m.MarshalToSizedBuffer(dAtA[:size])
-}
-
-func (m *PushSetServer) MarshalToSizedBuffer(dAtA []byte) (int, error) {
- i := len(dAtA)
- _ = i
- var l int
- _ = l
- if m.XXX_unrecognized != nil {
- i -= len(m.XXX_unrecognized)
- copy(dAtA[i:], m.XXX_unrecognized)
- }
- return len(dAtA) - i, nil
-}
-
-func (m *PushSetServer_Request) Marshal() (dAtA []byte, err error) {
- size := m.Size()
- dAtA = make([]byte, size)
- n, err := m.MarshalToSizedBuffer(dAtA[:size])
- if err != nil {
- return nil, err
- }
- return dAtA[:n], nil
-}
-
-func (m *PushSetServer_Request) MarshalTo(dAtA []byte) (int, error) {
- size := m.Size()
- return m.MarshalToSizedBuffer(dAtA[:size])
-}
-
-func (m *PushSetServer_Request) MarshalToSizedBuffer(dAtA []byte) (int, error) {
- i := len(dAtA)
- _ = i
- var l int
- _ = l
- if m.XXX_unrecognized != nil {
- i -= len(m.XXX_unrecognized)
- copy(dAtA[i:], m.XXX_unrecognized)
- }
- if m.Server != nil {
- {
- size, err := m.Server.MarshalToSizedBuffer(dAtA[:i])
- if err != nil {
- return 0, err
- }
- i -= size
- i = encodeVarintProtocoltypes(dAtA, i, uint64(size))
- }
- i--
- dAtA[i] = 0xa
- }
- return len(dAtA) - i, nil
-}
-
-func (m *PushSetServer_Reply) Marshal() (dAtA []byte, err error) {
- size := m.Size()
- dAtA = make([]byte, size)
- n, err := m.MarshalToSizedBuffer(dAtA[:size])
- if err != nil {
- return nil, err
- }
- return dAtA[:n], nil
-}
-
-func (m *PushSetServer_Reply) MarshalTo(dAtA []byte) (int, error) {
- size := m.Size()
- return m.MarshalToSizedBuffer(dAtA[:size])
-}
-
-func (m *PushSetServer_Reply) MarshalToSizedBuffer(dAtA []byte) (int, error) {
- i := len(dAtA)
- _ = i
- var l int
- _ = l
- if m.XXX_unrecognized != nil {
- i -= len(m.XXX_unrecognized)
- copy(dAtA[i:], m.XXX_unrecognized)
- }
- return len(dAtA) - i, nil
-}
-
func (m *FirstLastCounters) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
@@ -20055,7 +19319,7 @@ func (m *GroupAddMemberDevice) Size() (n int) {
return n
}
-func (m *DeviceSecret) Size() (n int) {
+func (m *DeviceChainKey) Size() (n int) {
if m == nil {
return 0
}
@@ -20074,7 +19338,7 @@ func (m *DeviceSecret) Size() (n int) {
return n
}
-func (m *GroupAddDeviceSecret) Size() (n int) {
+func (m *GroupAddDeviceChainKey) Size() (n int) {
if m == nil {
return 0
}
@@ -23051,7 +22315,7 @@ func (m *PushMemberTokenUpdate) Size() (n int) {
return n
}
-func (m *PushReceive) Size() (n int) {
+func (m *OutOfStoreReceive) Size() (n int) {
if m == nil {
return 0
}
@@ -23063,7 +22327,7 @@ func (m *PushReceive) Size() (n int) {
return n
}
-func (m *PushReceive_Request) Size() (n int) {
+func (m *OutOfStoreReceive_Request) Size() (n int) {
if m == nil {
return 0
}
@@ -23079,7 +22343,7 @@ func (m *PushReceive_Request) Size() (n int) {
return n
}
-func (m *PushReceive_Reply) Size() (n int) {
+func (m *OutOfStoreReceive_Reply) Size() (n int) {
if m == nil {
return 0
}
@@ -23106,7 +22370,7 @@ func (m *PushReceive_Reply) Size() (n int) {
return n
}
-func (m *PushSend) Size() (n int) {
+func (m *OutOfStoreSeal) Size() (n int) {
if m == nil {
return 0
}
@@ -23118,7 +22382,7 @@ func (m *PushSend) Size() (n int) {
return n
}
-func (m *PushSend_Request) Size() (n int) {
+func (m *OutOfStoreSeal_Request) Size() (n int) {
if m == nil {
return 0
}
@@ -23132,158 +22396,22 @@ func (m *PushSend_Request) Size() (n int) {
if l > 0 {
n += 1 + l + sovProtocoltypes(uint64(l))
}
- if len(m.GroupMembers) > 0 {
- for _, e := range m.GroupMembers {
- l = e.Size()
- n += 1 + l + sovProtocoltypes(uint64(l))
- }
- }
- if m.XXX_unrecognized != nil {
- n += len(m.XXX_unrecognized)
- }
- return n
-}
-
-func (m *PushSend_Reply) Size() (n int) {
- if m == nil {
- return 0
- }
- var l int
- _ = l
- if len(m.GroupMembers) > 0 {
- for _, e := range m.GroupMembers {
- l = e.Size()
- n += 1 + l + sovProtocoltypes(uint64(l))
- }
- }
- if m.XXX_unrecognized != nil {
- n += len(m.XXX_unrecognized)
- }
- return n
-}
-
-func (m *PushShareToken) Size() (n int) {
- if m == nil {
- return 0
- }
- var l int
- _ = l
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
return n
}
-func (m *PushShareToken_Request) Size() (n int) {
+func (m *OutOfStoreSeal_Reply) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
- l = len(m.GroupPK)
+ l = len(m.Encrypted)
if l > 0 {
n += 1 + l + sovProtocoltypes(uint64(l))
}
- if m.Server != nil {
- l = m.Server.Size()
- n += 1 + l + sovProtocoltypes(uint64(l))
- }
- if m.Receiver != nil {
- l = m.Receiver.Size()
- n += 1 + l + sovProtocoltypes(uint64(l))
- }
- if m.XXX_unrecognized != nil {
- n += len(m.XXX_unrecognized)
- }
- return n
-}
-
-func (m *PushShareToken_Reply) Size() (n int) {
- if m == nil {
- return 0
- }
- var l int
- _ = l
- if m.XXX_unrecognized != nil {
- n += len(m.XXX_unrecognized)
- }
- return n
-}
-
-func (m *PushSetDeviceToken) Size() (n int) {
- if m == nil {
- return 0
- }
- var l int
- _ = l
- if m.XXX_unrecognized != nil {
- n += len(m.XXX_unrecognized)
- }
- return n
-}
-
-func (m *PushSetDeviceToken_Request) Size() (n int) {
- if m == nil {
- return 0
- }
- var l int
- _ = l
- if m.Receiver != nil {
- l = m.Receiver.Size()
- n += 1 + l + sovProtocoltypes(uint64(l))
- }
- if m.XXX_unrecognized != nil {
- n += len(m.XXX_unrecognized)
- }
- return n
-}
-
-func (m *PushSetDeviceToken_Reply) Size() (n int) {
- if m == nil {
- return 0
- }
- var l int
- _ = l
- if m.XXX_unrecognized != nil {
- n += len(m.XXX_unrecognized)
- }
- return n
-}
-
-func (m *PushSetServer) Size() (n int) {
- if m == nil {
- return 0
- }
- var l int
- _ = l
- if m.XXX_unrecognized != nil {
- n += len(m.XXX_unrecognized)
- }
- return n
-}
-
-func (m *PushSetServer_Request) Size() (n int) {
- if m == nil {
- return 0
- }
- var l int
- _ = l
- if m.Server != nil {
- l = m.Server.Size()
- n += 1 + l + sovProtocoltypes(uint64(l))
- }
- if m.XXX_unrecognized != nil {
- n += len(m.XXX_unrecognized)
- }
- return n
-}
-
-func (m *PushSetServer_Reply) Size() (n int) {
- if m == nil {
- return 0
- }
- var l int
- _ = l
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
@@ -25538,7 +24666,7 @@ func (m *GroupAddMemberDevice) Unmarshal(dAtA []byte) error {
}
return nil
}
-func (m *DeviceSecret) Unmarshal(dAtA []byte) error {
+func (m *DeviceChainKey) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
@@ -25561,10 +24689,10 @@ func (m *DeviceSecret) Unmarshal(dAtA []byte) error {
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
- return fmt.Errorf("proto: DeviceSecret: wiretype end group for non-group")
+ return fmt.Errorf("proto: DeviceChainKey: wiretype end group for non-group")
}
if fieldNum <= 0 {
- return fmt.Errorf("proto: DeviceSecret: illegal tag %d (wire type %d)", fieldNum, wire)
+ return fmt.Errorf("proto: DeviceChainKey: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
@@ -25642,7 +24770,7 @@ func (m *DeviceSecret) Unmarshal(dAtA []byte) error {
}
return nil
}
-func (m *GroupAddDeviceSecret) Unmarshal(dAtA []byte) error {
+func (m *GroupAddDeviceChainKey) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
@@ -25665,10 +24793,10 @@ func (m *GroupAddDeviceSecret) Unmarshal(dAtA []byte) error {
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
- return fmt.Errorf("proto: GroupAddDeviceSecret: wiretype end group for non-group")
+ return fmt.Errorf("proto: GroupAddDeviceChainKey: wiretype end group for non-group")
}
if fieldNum <= 0 {
- return fmt.Errorf("proto: GroupAddDeviceSecret: illegal tag %d (wire type %d)", fieldNum, wire)
+ return fmt.Errorf("proto: GroupAddDeviceChainKey: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
@@ -41952,7 +41080,7 @@ func (m *PushMemberTokenUpdate) Unmarshal(dAtA []byte) error {
}
return nil
}
-func (m *PushReceive) Unmarshal(dAtA []byte) error {
+func (m *OutOfStoreReceive) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
@@ -41975,10 +41103,10 @@ func (m *PushReceive) Unmarshal(dAtA []byte) error {
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
- return fmt.Errorf("proto: PushReceive: wiretype end group for non-group")
+ return fmt.Errorf("proto: OutOfStoreReceive: wiretype end group for non-group")
}
if fieldNum <= 0 {
- return fmt.Errorf("proto: PushReceive: illegal tag %d (wire type %d)", fieldNum, wire)
+ return fmt.Errorf("proto: OutOfStoreReceive: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
default:
@@ -42003,7 +41131,7 @@ func (m *PushReceive) Unmarshal(dAtA []byte) error {
}
return nil
}
-func (m *PushReceive_Request) Unmarshal(dAtA []byte) error {
+func (m *OutOfStoreReceive_Request) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
@@ -42088,7 +41216,7 @@ func (m *PushReceive_Request) Unmarshal(dAtA []byte) error {
}
return nil
}
-func (m *PushReceive_Reply) Unmarshal(dAtA []byte) error {
+func (m *OutOfStoreReceive_Reply) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
@@ -42263,7 +41391,7 @@ func (m *PushReceive_Reply) Unmarshal(dAtA []byte) error {
}
return nil
}
-func (m *PushSend) Unmarshal(dAtA []byte) error {
+func (m *OutOfStoreSeal) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
@@ -42286,10 +41414,10 @@ func (m *PushSend) Unmarshal(dAtA []byte) error {
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
- return fmt.Errorf("proto: PushSend: wiretype end group for non-group")
+ return fmt.Errorf("proto: OutOfStoreSeal: wiretype end group for non-group")
}
if fieldNum <= 0 {
- return fmt.Errorf("proto: PushSend: illegal tag %d (wire type %d)", fieldNum, wire)
+ return fmt.Errorf("proto: OutOfStoreSeal: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
default:
@@ -42314,7 +41442,7 @@ func (m *PushSend) Unmarshal(dAtA []byte) error {
}
return nil
}
-func (m *PushSend_Request) Unmarshal(dAtA []byte) error {
+func (m *OutOfStoreSeal_Request) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
@@ -42411,40 +41539,6 @@ func (m *PushSend_Request) Unmarshal(dAtA []byte) error {
m.GroupPublicKey = []byte{}
}
iNdEx = postIndex
- case 3:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field GroupMembers", wireType)
- }
- var msglen int
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowProtocoltypes
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- msglen |= int(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- if msglen < 0 {
- return ErrInvalidLengthProtocoltypes
- }
- postIndex := iNdEx + msglen
- if postIndex < 0 {
- return ErrInvalidLengthProtocoltypes
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- m.GroupMembers = append(m.GroupMembers, &MemberWithDevices{})
- if err := m.GroupMembers[len(m.GroupMembers)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
- return err
- }
- iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipProtocoltypes(dAtA[iNdEx:])
@@ -42467,7 +41561,7 @@ func (m *PushSend_Request) Unmarshal(dAtA []byte) error {
}
return nil
}
-func (m *PushSend_Reply) Unmarshal(dAtA []byte) error {
+func (m *OutOfStoreSeal_Reply) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
@@ -42498,143 +41592,7 @@ func (m *PushSend_Reply) Unmarshal(dAtA []byte) error {
switch fieldNum {
case 1:
if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field GroupMembers", wireType)
- }
- var msglen int
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowProtocoltypes
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- msglen |= int(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- if msglen < 0 {
- return ErrInvalidLengthProtocoltypes
- }
- postIndex := iNdEx + msglen
- if postIndex < 0 {
- return ErrInvalidLengthProtocoltypes
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- m.GroupMembers = append(m.GroupMembers, &MemberWithDevices{})
- if err := m.GroupMembers[len(m.GroupMembers)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
- return err
- }
- iNdEx = postIndex
- default:
- iNdEx = preIndex
- skippy, err := skipProtocoltypes(dAtA[iNdEx:])
- if err != nil {
- return err
- }
- if (skippy < 0) || (iNdEx+skippy) < 0 {
- return ErrInvalidLengthProtocoltypes
- }
- if (iNdEx + skippy) > l {
- return io.ErrUnexpectedEOF
- }
- m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
- iNdEx += skippy
- }
- }
-
- if iNdEx > l {
- return io.ErrUnexpectedEOF
- }
- return nil
-}
-func (m *PushShareToken) Unmarshal(dAtA []byte) error {
- l := len(dAtA)
- iNdEx := 0
- for iNdEx < l {
- preIndex := iNdEx
- var wire uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowProtocoltypes
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- wire |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- fieldNum := int32(wire >> 3)
- wireType := int(wire & 0x7)
- if wireType == 4 {
- return fmt.Errorf("proto: PushShareToken: wiretype end group for non-group")
- }
- if fieldNum <= 0 {
- return fmt.Errorf("proto: PushShareToken: illegal tag %d (wire type %d)", fieldNum, wire)
- }
- switch fieldNum {
- default:
- iNdEx = preIndex
- skippy, err := skipProtocoltypes(dAtA[iNdEx:])
- if err != nil {
- return err
- }
- if (skippy < 0) || (iNdEx+skippy) < 0 {
- return ErrInvalidLengthProtocoltypes
- }
- if (iNdEx + skippy) > l {
- return io.ErrUnexpectedEOF
- }
- m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
- iNdEx += skippy
- }
- }
-
- if iNdEx > l {
- return io.ErrUnexpectedEOF
- }
- return nil
-}
-func (m *PushShareToken_Request) Unmarshal(dAtA []byte) error {
- l := len(dAtA)
- iNdEx := 0
- for iNdEx < l {
- preIndex := iNdEx
- var wire uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowProtocoltypes
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- wire |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- fieldNum := int32(wire >> 3)
- wireType := int(wire & 0x7)
- if wireType == 4 {
- return fmt.Errorf("proto: Request: wiretype end group for non-group")
- }
- if fieldNum <= 0 {
- return fmt.Errorf("proto: Request: illegal tag %d (wire type %d)", fieldNum, wire)
- }
- switch fieldNum {
- case 1:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field GroupPK", wireType)
+ return fmt.Errorf("proto: wrong wireType = %d for field Encrypted", wireType)
}
var byteLen int
for shift := uint(0); ; shift += 7 {
@@ -42661,81 +41619,9 @@ func (m *PushShareToken_Request) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
- m.GroupPK = append(m.GroupPK[:0], dAtA[iNdEx:postIndex]...)
- if m.GroupPK == nil {
- m.GroupPK = []byte{}
- }
- iNdEx = postIndex
- case 2:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field Server", wireType)
- }
- var msglen int
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowProtocoltypes
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- msglen |= int(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- if msglen < 0 {
- return ErrInvalidLengthProtocoltypes
- }
- postIndex := iNdEx + msglen
- if postIndex < 0 {
- return ErrInvalidLengthProtocoltypes
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- if m.Server == nil {
- m.Server = &PushServer{}
- }
- if err := m.Server.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
- return err
- }
- iNdEx = postIndex
- case 3:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field Receiver", wireType)
- }
- var msglen int
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowProtocoltypes
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- msglen |= int(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- if msglen < 0 {
- return ErrInvalidLengthProtocoltypes
- }
- postIndex := iNdEx + msglen
- if postIndex < 0 {
- return ErrInvalidLengthProtocoltypes
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- if m.Receiver == nil {
- m.Receiver = &PushServiceReceiver{}
- }
- if err := m.Receiver.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
- return err
+ m.Encrypted = append(m.Encrypted[:0], dAtA[iNdEx:postIndex]...)
+ if m.Encrypted == nil {
+ m.Encrypted = []byte{}
}
iNdEx = postIndex
default:
@@ -42760,435 +41646,6 @@ func (m *PushShareToken_Request) Unmarshal(dAtA []byte) error {
}
return nil
}
-func (m *PushShareToken_Reply) Unmarshal(dAtA []byte) error {
- l := len(dAtA)
- iNdEx := 0
- for iNdEx < l {
- preIndex := iNdEx
- var wire uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowProtocoltypes
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- wire |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- fieldNum := int32(wire >> 3)
- wireType := int(wire & 0x7)
- if wireType == 4 {
- return fmt.Errorf("proto: Reply: wiretype end group for non-group")
- }
- if fieldNum <= 0 {
- return fmt.Errorf("proto: Reply: illegal tag %d (wire type %d)", fieldNum, wire)
- }
- switch fieldNum {
- default:
- iNdEx = preIndex
- skippy, err := skipProtocoltypes(dAtA[iNdEx:])
- if err != nil {
- return err
- }
- if (skippy < 0) || (iNdEx+skippy) < 0 {
- return ErrInvalidLengthProtocoltypes
- }
- if (iNdEx + skippy) > l {
- return io.ErrUnexpectedEOF
- }
- m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
- iNdEx += skippy
- }
- }
-
- if iNdEx > l {
- return io.ErrUnexpectedEOF
- }
- return nil
-}
-func (m *PushSetDeviceToken) Unmarshal(dAtA []byte) error {
- l := len(dAtA)
- iNdEx := 0
- for iNdEx < l {
- preIndex := iNdEx
- var wire uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowProtocoltypes
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- wire |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- fieldNum := int32(wire >> 3)
- wireType := int(wire & 0x7)
- if wireType == 4 {
- return fmt.Errorf("proto: PushSetDeviceToken: wiretype end group for non-group")
- }
- if fieldNum <= 0 {
- return fmt.Errorf("proto: PushSetDeviceToken: illegal tag %d (wire type %d)", fieldNum, wire)
- }
- switch fieldNum {
- default:
- iNdEx = preIndex
- skippy, err := skipProtocoltypes(dAtA[iNdEx:])
- if err != nil {
- return err
- }
- if (skippy < 0) || (iNdEx+skippy) < 0 {
- return ErrInvalidLengthProtocoltypes
- }
- if (iNdEx + skippy) > l {
- return io.ErrUnexpectedEOF
- }
- m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
- iNdEx += skippy
- }
- }
-
- if iNdEx > l {
- return io.ErrUnexpectedEOF
- }
- return nil
-}
-func (m *PushSetDeviceToken_Request) Unmarshal(dAtA []byte) error {
- l := len(dAtA)
- iNdEx := 0
- for iNdEx < l {
- preIndex := iNdEx
- var wire uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowProtocoltypes
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- wire |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- fieldNum := int32(wire >> 3)
- wireType := int(wire & 0x7)
- if wireType == 4 {
- return fmt.Errorf("proto: Request: wiretype end group for non-group")
- }
- if fieldNum <= 0 {
- return fmt.Errorf("proto: Request: illegal tag %d (wire type %d)", fieldNum, wire)
- }
- switch fieldNum {
- case 1:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field Receiver", wireType)
- }
- var msglen int
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowProtocoltypes
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- msglen |= int(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- if msglen < 0 {
- return ErrInvalidLengthProtocoltypes
- }
- postIndex := iNdEx + msglen
- if postIndex < 0 {
- return ErrInvalidLengthProtocoltypes
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- if m.Receiver == nil {
- m.Receiver = &PushServiceReceiver{}
- }
- if err := m.Receiver.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
- return err
- }
- iNdEx = postIndex
- default:
- iNdEx = preIndex
- skippy, err := skipProtocoltypes(dAtA[iNdEx:])
- if err != nil {
- return err
- }
- if (skippy < 0) || (iNdEx+skippy) < 0 {
- return ErrInvalidLengthProtocoltypes
- }
- if (iNdEx + skippy) > l {
- return io.ErrUnexpectedEOF
- }
- m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
- iNdEx += skippy
- }
- }
-
- if iNdEx > l {
- return io.ErrUnexpectedEOF
- }
- return nil
-}
-func (m *PushSetDeviceToken_Reply) Unmarshal(dAtA []byte) error {
- l := len(dAtA)
- iNdEx := 0
- for iNdEx < l {
- preIndex := iNdEx
- var wire uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowProtocoltypes
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- wire |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- fieldNum := int32(wire >> 3)
- wireType := int(wire & 0x7)
- if wireType == 4 {
- return fmt.Errorf("proto: Reply: wiretype end group for non-group")
- }
- if fieldNum <= 0 {
- return fmt.Errorf("proto: Reply: illegal tag %d (wire type %d)", fieldNum, wire)
- }
- switch fieldNum {
- default:
- iNdEx = preIndex
- skippy, err := skipProtocoltypes(dAtA[iNdEx:])
- if err != nil {
- return err
- }
- if (skippy < 0) || (iNdEx+skippy) < 0 {
- return ErrInvalidLengthProtocoltypes
- }
- if (iNdEx + skippy) > l {
- return io.ErrUnexpectedEOF
- }
- m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
- iNdEx += skippy
- }
- }
-
- if iNdEx > l {
- return io.ErrUnexpectedEOF
- }
- return nil
-}
-func (m *PushSetServer) Unmarshal(dAtA []byte) error {
- l := len(dAtA)
- iNdEx := 0
- for iNdEx < l {
- preIndex := iNdEx
- var wire uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowProtocoltypes
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- wire |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- fieldNum := int32(wire >> 3)
- wireType := int(wire & 0x7)
- if wireType == 4 {
- return fmt.Errorf("proto: PushSetServer: wiretype end group for non-group")
- }
- if fieldNum <= 0 {
- return fmt.Errorf("proto: PushSetServer: illegal tag %d (wire type %d)", fieldNum, wire)
- }
- switch fieldNum {
- default:
- iNdEx = preIndex
- skippy, err := skipProtocoltypes(dAtA[iNdEx:])
- if err != nil {
- return err
- }
- if (skippy < 0) || (iNdEx+skippy) < 0 {
- return ErrInvalidLengthProtocoltypes
- }
- if (iNdEx + skippy) > l {
- return io.ErrUnexpectedEOF
- }
- m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
- iNdEx += skippy
- }
- }
-
- if iNdEx > l {
- return io.ErrUnexpectedEOF
- }
- return nil
-}
-func (m *PushSetServer_Request) Unmarshal(dAtA []byte) error {
- l := len(dAtA)
- iNdEx := 0
- for iNdEx < l {
- preIndex := iNdEx
- var wire uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowProtocoltypes
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- wire |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- fieldNum := int32(wire >> 3)
- wireType := int(wire & 0x7)
- if wireType == 4 {
- return fmt.Errorf("proto: Request: wiretype end group for non-group")
- }
- if fieldNum <= 0 {
- return fmt.Errorf("proto: Request: illegal tag %d (wire type %d)", fieldNum, wire)
- }
- switch fieldNum {
- case 1:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field Server", wireType)
- }
- var msglen int
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowProtocoltypes
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- msglen |= int(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- if msglen < 0 {
- return ErrInvalidLengthProtocoltypes
- }
- postIndex := iNdEx + msglen
- if postIndex < 0 {
- return ErrInvalidLengthProtocoltypes
- }
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- if m.Server == nil {
- m.Server = &PushServer{}
- }
- if err := m.Server.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
- return err
- }
- iNdEx = postIndex
- default:
- iNdEx = preIndex
- skippy, err := skipProtocoltypes(dAtA[iNdEx:])
- if err != nil {
- return err
- }
- if (skippy < 0) || (iNdEx+skippy) < 0 {
- return ErrInvalidLengthProtocoltypes
- }
- if (iNdEx + skippy) > l {
- return io.ErrUnexpectedEOF
- }
- m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
- iNdEx += skippy
- }
- }
-
- if iNdEx > l {
- return io.ErrUnexpectedEOF
- }
- return nil
-}
-func (m *PushSetServer_Reply) Unmarshal(dAtA []byte) error {
- l := len(dAtA)
- iNdEx := 0
- for iNdEx < l {
- preIndex := iNdEx
- var wire uint64
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowProtocoltypes
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- wire |= uint64(b&0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- fieldNum := int32(wire >> 3)
- wireType := int(wire & 0x7)
- if wireType == 4 {
- return fmt.Errorf("proto: Reply: wiretype end group for non-group")
- }
- if fieldNum <= 0 {
- return fmt.Errorf("proto: Reply: illegal tag %d (wire type %d)", fieldNum, wire)
- }
- switch fieldNum {
- default:
- iNdEx = preIndex
- skippy, err := skipProtocoltypes(dAtA[iNdEx:])
- if err != nil {
- return err
- }
- if (skippy < 0) || (iNdEx+skippy) < 0 {
- return ErrInvalidLengthProtocoltypes
- }
- if (iNdEx + skippy) > l {
- return io.ErrUnexpectedEOF
- }
- m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
- iNdEx += skippy
- }
- }
-
- if iNdEx > l {
- return io.ErrUnexpectedEOF
- }
- return nil
-}
func (m *FirstLastCounters) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
diff --git a/pkg/protocoltypes/protocoltypes.pb.gw.go b/pkg/protocoltypes/protocoltypes.pb.gw.go
index cfdbafd9..501f915d 100644
--- a/pkg/protocoltypes/protocoltypes.pb.gw.go
+++ b/pkg/protocoltypes/protocoltypes.pb.gw.go
@@ -1287,8 +1287,8 @@ func local_request_ProtocolService_PeerList_0(ctx context.Context, marshaler run
}
-func request_ProtocolService_PushReceive_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
- var protoReq PushReceive_Request
+func request_ProtocolService_OutOfStoreReceive_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+ var protoReq OutOfStoreReceive_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
@@ -1299,13 +1299,13 @@ func request_ProtocolService_PushReceive_0(ctx context.Context, marshaler runtim
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
- msg, err := client.PushReceive(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+ msg, err := client.OutOfStoreReceive(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
-func local_request_ProtocolService_PushReceive_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
- var protoReq PushReceive_Request
+func local_request_ProtocolService_OutOfStoreReceive_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+ var protoReq OutOfStoreReceive_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
@@ -1316,13 +1316,13 @@ func local_request_ProtocolService_PushReceive_0(ctx context.Context, marshaler
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
- msg, err := server.PushReceive(ctx, &protoReq)
+ msg, err := server.OutOfStoreReceive(ctx, &protoReq)
return msg, metadata, err
}
-func request_ProtocolService_PushSend_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
- var protoReq PushSend_Request
+func request_ProtocolService_OutOfStoreSeal_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+ var protoReq OutOfStoreSeal_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
@@ -1333,13 +1333,13 @@ func request_ProtocolService_PushSend_0(ctx context.Context, marshaler runtime.M
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
- msg, err := client.PushSend(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+ msg, err := client.OutOfStoreSeal(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
-func local_request_ProtocolService_PushSend_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
- var protoReq PushSend_Request
+func local_request_ProtocolService_OutOfStoreSeal_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+ var protoReq OutOfStoreSeal_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
@@ -1350,109 +1350,7 @@ func local_request_ProtocolService_PushSend_0(ctx context.Context, marshaler run
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
- msg, err := server.PushSend(ctx, &protoReq)
- return msg, metadata, err
-
-}
-
-func request_ProtocolService_PushShareToken_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
- var protoReq PushShareToken_Request
- var metadata runtime.ServerMetadata
-
- newReader, berr := utilities.IOReaderFactory(req.Body)
- if berr != nil {
- return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
- }
- if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
- return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
- }
-
- msg, err := client.PushShareToken(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
- return msg, metadata, err
-
-}
-
-func local_request_ProtocolService_PushShareToken_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
- var protoReq PushShareToken_Request
- var metadata runtime.ServerMetadata
-
- newReader, berr := utilities.IOReaderFactory(req.Body)
- if berr != nil {
- return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
- }
- if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
- return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
- }
-
- msg, err := server.PushShareToken(ctx, &protoReq)
- return msg, metadata, err
-
-}
-
-func request_ProtocolService_PushSetDeviceToken_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
- var protoReq PushSetDeviceToken_Request
- var metadata runtime.ServerMetadata
-
- newReader, berr := utilities.IOReaderFactory(req.Body)
- if berr != nil {
- return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
- }
- if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
- return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
- }
-
- msg, err := client.PushSetDeviceToken(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
- return msg, metadata, err
-
-}
-
-func local_request_ProtocolService_PushSetDeviceToken_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
- var protoReq PushSetDeviceToken_Request
- var metadata runtime.ServerMetadata
-
- newReader, berr := utilities.IOReaderFactory(req.Body)
- if berr != nil {
- return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
- }
- if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
- return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
- }
-
- msg, err := server.PushSetDeviceToken(ctx, &protoReq)
- return msg, metadata, err
-
-}
-
-func request_ProtocolService_PushSetServer_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
- var protoReq PushSetServer_Request
- var metadata runtime.ServerMetadata
-
- newReader, berr := utilities.IOReaderFactory(req.Body)
- if berr != nil {
- return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
- }
- if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
- return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
- }
-
- msg, err := client.PushSetServer(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
- return msg, metadata, err
-
-}
-
-func local_request_ProtocolService_PushSetServer_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
- var protoReq PushSetServer_Request
- var metadata runtime.ServerMetadata
-
- newReader, berr := utilities.IOReaderFactory(req.Body)
- if berr != nil {
- return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
- }
- if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
- return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
- }
-
- msg, err := server.PushSetServer(ctx, &protoReq)
+ msg, err := server.OutOfStoreSeal(ctx, &protoReq)
return msg, metadata, err
}
@@ -2266,7 +2164,7 @@ func RegisterProtocolServiceHandlerServer(ctx context.Context, mux *runtime.Serv
})
- mux.Handle("POST", pattern_ProtocolService_PushReceive_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+ mux.Handle("POST", pattern_ProtocolService_OutOfStoreReceive_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
@@ -2277,7 +2175,7 @@ func RegisterProtocolServiceHandlerServer(ctx context.Context, mux *runtime.Serv
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
- resp, md, err := local_request_ProtocolService_PushReceive_0(rctx, inboundMarshaler, server, req, pathParams)
+ resp, md, err := local_request_ProtocolService_OutOfStoreReceive_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
@@ -2285,11 +2183,11 @@ func RegisterProtocolServiceHandlerServer(ctx context.Context, mux *runtime.Serv
return
}
- forward_ProtocolService_PushReceive_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+ forward_ProtocolService_OutOfStoreReceive_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
- mux.Handle("POST", pattern_ProtocolService_PushSend_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+ mux.Handle("POST", pattern_ProtocolService_OutOfStoreSeal_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
@@ -2300,7 +2198,7 @@ func RegisterProtocolServiceHandlerServer(ctx context.Context, mux *runtime.Serv
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
- resp, md, err := local_request_ProtocolService_PushSend_0(rctx, inboundMarshaler, server, req, pathParams)
+ resp, md, err := local_request_ProtocolService_OutOfStoreSeal_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
@@ -2308,76 +2206,7 @@ func RegisterProtocolServiceHandlerServer(ctx context.Context, mux *runtime.Serv
return
}
- forward_ProtocolService_PushSend_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
-
- })
-
- mux.Handle("POST", pattern_ProtocolService_PushShareToken_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
- ctx, cancel := context.WithCancel(req.Context())
- defer cancel()
- var stream runtime.ServerTransportStream
- ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
- inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
- rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
- if err != nil {
- runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
- return
- }
- resp, md, err := local_request_ProtocolService_PushShareToken_0(rctx, inboundMarshaler, server, req, pathParams)
- md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
- ctx = runtime.NewServerMetadataContext(ctx, md)
- if err != nil {
- runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
- return
- }
-
- forward_ProtocolService_PushShareToken_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
-
- })
-
- mux.Handle("POST", pattern_ProtocolService_PushSetDeviceToken_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
- ctx, cancel := context.WithCancel(req.Context())
- defer cancel()
- var stream runtime.ServerTransportStream
- ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
- inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
- rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
- if err != nil {
- runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
- return
- }
- resp, md, err := local_request_ProtocolService_PushSetDeviceToken_0(rctx, inboundMarshaler, server, req, pathParams)
- md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
- ctx = runtime.NewServerMetadataContext(ctx, md)
- if err != nil {
- runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
- return
- }
-
- forward_ProtocolService_PushSetDeviceToken_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
-
- })
-
- mux.Handle("POST", pattern_ProtocolService_PushSetServer_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
- ctx, cancel := context.WithCancel(req.Context())
- defer cancel()
- var stream runtime.ServerTransportStream
- ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
- inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
- rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
- if err != nil {
- runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
- return
- }
- resp, md, err := local_request_ProtocolService_PushSetServer_0(rctx, inboundMarshaler, server, req, pathParams)
- md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
- ctx = runtime.NewServerMetadataContext(ctx, md)
- if err != nil {
- runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
- return
- }
-
- forward_ProtocolService_PushSetServer_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+ forward_ProtocolService_OutOfStoreSeal_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
@@ -3225,47 +3054,7 @@ func RegisterProtocolServiceHandlerClient(ctx context.Context, mux *runtime.Serv
})
- mux.Handle("POST", pattern_ProtocolService_PushReceive_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
- ctx, cancel := context.WithCancel(req.Context())
- defer cancel()
- inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
- rctx, err := runtime.AnnotateContext(ctx, mux, req)
- if err != nil {
- runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
- return
- }
- resp, md, err := request_ProtocolService_PushReceive_0(rctx, inboundMarshaler, client, req, pathParams)
- ctx = runtime.NewServerMetadataContext(ctx, md)
- if err != nil {
- runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
- return
- }
-
- forward_ProtocolService_PushReceive_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
-
- })
-
- mux.Handle("POST", pattern_ProtocolService_PushSend_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
- ctx, cancel := context.WithCancel(req.Context())
- defer cancel()
- inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
- rctx, err := runtime.AnnotateContext(ctx, mux, req)
- if err != nil {
- runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
- return
- }
- resp, md, err := request_ProtocolService_PushSend_0(rctx, inboundMarshaler, client, req, pathParams)
- ctx = runtime.NewServerMetadataContext(ctx, md)
- if err != nil {
- runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
- return
- }
-
- forward_ProtocolService_PushSend_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
-
- })
-
- mux.Handle("POST", pattern_ProtocolService_PushShareToken_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+ mux.Handle("POST", pattern_ProtocolService_OutOfStoreReceive_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
@@ -3274,18 +3063,18 @@ func RegisterProtocolServiceHandlerClient(ctx context.Context, mux *runtime.Serv
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
- resp, md, err := request_ProtocolService_PushShareToken_0(rctx, inboundMarshaler, client, req, pathParams)
+ resp, md, err := request_ProtocolService_OutOfStoreReceive_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
- forward_ProtocolService_PushShareToken_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+ forward_ProtocolService_OutOfStoreReceive_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
- mux.Handle("POST", pattern_ProtocolService_PushSetDeviceToken_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+ mux.Handle("POST", pattern_ProtocolService_OutOfStoreSeal_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
@@ -3294,34 +3083,14 @@ func RegisterProtocolServiceHandlerClient(ctx context.Context, mux *runtime.Serv
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
- resp, md, err := request_ProtocolService_PushSetDeviceToken_0(rctx, inboundMarshaler, client, req, pathParams)
+ resp, md, err := request_ProtocolService_OutOfStoreSeal_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
- forward_ProtocolService_PushSetDeviceToken_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
-
- })
-
- mux.Handle("POST", pattern_ProtocolService_PushSetServer_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
- ctx, cancel := context.WithCancel(req.Context())
- defer cancel()
- inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
- rctx, err := runtime.AnnotateContext(ctx, mux, req)
- if err != nil {
- runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
- return
- }
- resp, md, err := request_ProtocolService_PushSetServer_0(rctx, inboundMarshaler, client, req, pathParams)
- ctx = runtime.NewServerMetadataContext(ctx, md)
- if err != nil {
- runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
- return
- }
-
- forward_ProtocolService_PushSetServer_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+ forward_ProtocolService_OutOfStoreSeal_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
@@ -3427,15 +3196,9 @@ var (
pattern_ProtocolService_PeerList_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "PeerList"}, "", runtime.AssumeColonVerbOpt(true)))
- pattern_ProtocolService_PushReceive_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "PushReceive"}, "", runtime.AssumeColonVerbOpt(true)))
+ pattern_ProtocolService_OutOfStoreReceive_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "OutOfStoreReceive"}, "", runtime.AssumeColonVerbOpt(true)))
- pattern_ProtocolService_PushSend_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "PushSend"}, "", runtime.AssumeColonVerbOpt(true)))
-
- pattern_ProtocolService_PushShareToken_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "PushShareToken"}, "", runtime.AssumeColonVerbOpt(true)))
-
- pattern_ProtocolService_PushSetDeviceToken_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "PushSetDeviceToken"}, "", runtime.AssumeColonVerbOpt(true)))
-
- pattern_ProtocolService_PushSetServer_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "PushSetServer"}, "", runtime.AssumeColonVerbOpt(true)))
+ pattern_ProtocolService_OutOfStoreSeal_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "OutOfStoreSeal"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_RefreshContactRequest_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "RefreshContactRequest"}, "", runtime.AssumeColonVerbOpt(true)))
)
@@ -3519,15 +3282,9 @@ var (
forward_ProtocolService_PeerList_0 = runtime.ForwardResponseMessage
- forward_ProtocolService_PushReceive_0 = runtime.ForwardResponseMessage
-
- forward_ProtocolService_PushSend_0 = runtime.ForwardResponseMessage
-
- forward_ProtocolService_PushShareToken_0 = runtime.ForwardResponseMessage
-
- forward_ProtocolService_PushSetDeviceToken_0 = runtime.ForwardResponseMessage
+ forward_ProtocolService_OutOfStoreReceive_0 = runtime.ForwardResponseMessage
- forward_ProtocolService_PushSetServer_0 = runtime.ForwardResponseMessage
+ forward_ProtocolService_OutOfStoreSeal_0 = runtime.ForwardResponseMessage
forward_ProtocolService_RefreshContactRequest_0 = runtime.ForwardResponseMessage
)
diff --git a/pkg/protocoltypes/protocoltypes_grpc.pb.go b/pkg/protocoltypes/protocoltypes_grpc.pb.go
index 003db871..e60c9048 100644
--- a/pkg/protocoltypes/protocoltypes_grpc.pb.go
+++ b/pkg/protocoltypes/protocoltypes_grpc.pb.go
@@ -91,16 +91,10 @@ type ProtocolServiceClient interface {
ReplicationServiceRegisterGroup(ctx context.Context, in *ReplicationServiceRegisterGroup_Request, opts ...grpc.CallOption) (*ReplicationServiceRegisterGroup_Reply, error)
// PeerList returns a list of P2P peers
PeerList(ctx context.Context, in *PeerList_Request, opts ...grpc.CallOption) (*PeerList_Reply, error)
- // PushReceive handles a push payload, decrypts it if possible
- PushReceive(ctx context.Context, in *PushReceive_Request, opts ...grpc.CallOption) (*PushReceive_Reply, error)
- // PushSend sends a push payload to a specified list of group members
- PushSend(ctx context.Context, in *PushSend_Request, opts ...grpc.CallOption) (*PushSend_Reply, error)
- // PushShareToken sends push tokens of own devices to a group
- PushShareToken(ctx context.Context, in *PushShareToken_Request, opts ...grpc.CallOption) (*PushShareToken_Reply, error)
- // PushSetDeviceToken registers a push token for the current device
- PushSetDeviceToken(ctx context.Context, in *PushSetDeviceToken_Request, opts ...grpc.CallOption) (*PushSetDeviceToken_Reply, error)
- // PushSetServer registers a push server for the current device
- PushSetServer(ctx context.Context, in *PushSetServer_Request, opts ...grpc.CallOption) (*PushSetServer_Reply, error)
+ // OutOfStoreReceive parses a payload received outside a synchronized store
+ OutOfStoreReceive(ctx context.Context, in *OutOfStoreReceive_Request, opts ...grpc.CallOption) (*OutOfStoreReceive_Reply, error)
+ // OutOfStoreSeal creates a payload of a message present in store to be sent outside a synchronized store
+ OutOfStoreSeal(ctx context.Context, in *OutOfStoreSeal_Request, opts ...grpc.CallOption) (*OutOfStoreSeal_Reply, error)
// RefreshContactRequest try to refresh the contact request for the given contact
RefreshContactRequest(ctx context.Context, in *RefreshContactRequest_Request, opts ...grpc.CallOption) (*RefreshContactRequest_Reply, error)
}
@@ -648,45 +642,18 @@ func (c *protocolServiceClient) PeerList(ctx context.Context, in *PeerList_Reque
return out, nil
}
-func (c *protocolServiceClient) PushReceive(ctx context.Context, in *PushReceive_Request, opts ...grpc.CallOption) (*PushReceive_Reply, error) {
- out := new(PushReceive_Reply)
- err := c.cc.Invoke(ctx, "/weshnet.protocol.v1.ProtocolService/PushReceive", in, out, opts...)
+func (c *protocolServiceClient) OutOfStoreReceive(ctx context.Context, in *OutOfStoreReceive_Request, opts ...grpc.CallOption) (*OutOfStoreReceive_Reply, error) {
+ out := new(OutOfStoreReceive_Reply)
+ err := c.cc.Invoke(ctx, "/weshnet.protocol.v1.ProtocolService/OutOfStoreReceive", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
-func (c *protocolServiceClient) PushSend(ctx context.Context, in *PushSend_Request, opts ...grpc.CallOption) (*PushSend_Reply, error) {
- out := new(PushSend_Reply)
- err := c.cc.Invoke(ctx, "/weshnet.protocol.v1.ProtocolService/PushSend", in, out, opts...)
- if err != nil {
- return nil, err
- }
- return out, nil
-}
-
-func (c *protocolServiceClient) PushShareToken(ctx context.Context, in *PushShareToken_Request, opts ...grpc.CallOption) (*PushShareToken_Reply, error) {
- out := new(PushShareToken_Reply)
- err := c.cc.Invoke(ctx, "/weshnet.protocol.v1.ProtocolService/PushShareToken", in, out, opts...)
- if err != nil {
- return nil, err
- }
- return out, nil
-}
-
-func (c *protocolServiceClient) PushSetDeviceToken(ctx context.Context, in *PushSetDeviceToken_Request, opts ...grpc.CallOption) (*PushSetDeviceToken_Reply, error) {
- out := new(PushSetDeviceToken_Reply)
- err := c.cc.Invoke(ctx, "/weshnet.protocol.v1.ProtocolService/PushSetDeviceToken", in, out, opts...)
- if err != nil {
- return nil, err
- }
- return out, nil
-}
-
-func (c *protocolServiceClient) PushSetServer(ctx context.Context, in *PushSetServer_Request, opts ...grpc.CallOption) (*PushSetServer_Reply, error) {
- out := new(PushSetServer_Reply)
- err := c.cc.Invoke(ctx, "/weshnet.protocol.v1.ProtocolService/PushSetServer", in, out, opts...)
+func (c *protocolServiceClient) OutOfStoreSeal(ctx context.Context, in *OutOfStoreSeal_Request, opts ...grpc.CallOption) (*OutOfStoreSeal_Reply, error) {
+ out := new(OutOfStoreSeal_Reply)
+ err := c.cc.Invoke(ctx, "/weshnet.protocol.v1.ProtocolService/OutOfStoreSeal", in, out, opts...)
if err != nil {
return nil, err
}
@@ -779,16 +746,10 @@ type ProtocolServiceServer interface {
ReplicationServiceRegisterGroup(context.Context, *ReplicationServiceRegisterGroup_Request) (*ReplicationServiceRegisterGroup_Reply, error)
// PeerList returns a list of P2P peers
PeerList(context.Context, *PeerList_Request) (*PeerList_Reply, error)
- // PushReceive handles a push payload, decrypts it if possible
- PushReceive(context.Context, *PushReceive_Request) (*PushReceive_Reply, error)
- // PushSend sends a push payload to a specified list of group members
- PushSend(context.Context, *PushSend_Request) (*PushSend_Reply, error)
- // PushShareToken sends push tokens of own devices to a group
- PushShareToken(context.Context, *PushShareToken_Request) (*PushShareToken_Reply, error)
- // PushSetDeviceToken registers a push token for the current device
- PushSetDeviceToken(context.Context, *PushSetDeviceToken_Request) (*PushSetDeviceToken_Reply, error)
- // PushSetServer registers a push server for the current device
- PushSetServer(context.Context, *PushSetServer_Request) (*PushSetServer_Reply, error)
+ // OutOfStoreReceive parses a payload received outside a synchronized store
+ OutOfStoreReceive(context.Context, *OutOfStoreReceive_Request) (*OutOfStoreReceive_Reply, error)
+ // OutOfStoreSeal creates a payload of a message present in store to be sent outside a synchronized store
+ OutOfStoreSeal(context.Context, *OutOfStoreSeal_Request) (*OutOfStoreSeal_Reply, error)
// RefreshContactRequest try to refresh the contact request for the given contact
RefreshContactRequest(context.Context, *RefreshContactRequest_Request) (*RefreshContactRequest_Reply, error)
mustEmbedUnimplementedProtocolServiceServer()
@@ -915,20 +876,11 @@ func (UnimplementedProtocolServiceServer) ReplicationServiceRegisterGroup(contex
func (UnimplementedProtocolServiceServer) PeerList(context.Context, *PeerList_Request) (*PeerList_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method PeerList not implemented")
}
-func (UnimplementedProtocolServiceServer) PushReceive(context.Context, *PushReceive_Request) (*PushReceive_Reply, error) {
- return nil, status.Errorf(codes.Unimplemented, "method PushReceive not implemented")
-}
-func (UnimplementedProtocolServiceServer) PushSend(context.Context, *PushSend_Request) (*PushSend_Reply, error) {
- return nil, status.Errorf(codes.Unimplemented, "method PushSend not implemented")
-}
-func (UnimplementedProtocolServiceServer) PushShareToken(context.Context, *PushShareToken_Request) (*PushShareToken_Reply, error) {
- return nil, status.Errorf(codes.Unimplemented, "method PushShareToken not implemented")
-}
-func (UnimplementedProtocolServiceServer) PushSetDeviceToken(context.Context, *PushSetDeviceToken_Request) (*PushSetDeviceToken_Reply, error) {
- return nil, status.Errorf(codes.Unimplemented, "method PushSetDeviceToken not implemented")
+func (UnimplementedProtocolServiceServer) OutOfStoreReceive(context.Context, *OutOfStoreReceive_Request) (*OutOfStoreReceive_Reply, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method OutOfStoreReceive not implemented")
}
-func (UnimplementedProtocolServiceServer) PushSetServer(context.Context, *PushSetServer_Request) (*PushSetServer_Reply, error) {
- return nil, status.Errorf(codes.Unimplemented, "method PushSetServer not implemented")
+func (UnimplementedProtocolServiceServer) OutOfStoreSeal(context.Context, *OutOfStoreSeal_Request) (*OutOfStoreSeal_Reply, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method OutOfStoreSeal not implemented")
}
func (UnimplementedProtocolServiceServer) RefreshContactRequest(context.Context, *RefreshContactRequest_Request) (*RefreshContactRequest_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method RefreshContactRequest not implemented")
@@ -1672,92 +1624,38 @@ func _ProtocolService_PeerList_Handler(srv interface{}, ctx context.Context, dec
return interceptor(ctx, in, info, handler)
}
-func _ProtocolService_PushReceive_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
- in := new(PushReceive_Request)
- if err := dec(in); err != nil {
- return nil, err
- }
- if interceptor == nil {
- return srv.(ProtocolServiceServer).PushReceive(ctx, in)
- }
- info := &grpc.UnaryServerInfo{
- Server: srv,
- FullMethod: "/weshnet.protocol.v1.ProtocolService/PushReceive",
- }
- handler := func(ctx context.Context, req interface{}) (interface{}, error) {
- return srv.(ProtocolServiceServer).PushReceive(ctx, req.(*PushReceive_Request))
- }
- return interceptor(ctx, in, info, handler)
-}
-
-func _ProtocolService_PushSend_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
- in := new(PushSend_Request)
+func _ProtocolService_OutOfStoreReceive_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(OutOfStoreReceive_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
- return srv.(ProtocolServiceServer).PushSend(ctx, in)
+ return srv.(ProtocolServiceServer).OutOfStoreReceive(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
- FullMethod: "/weshnet.protocol.v1.ProtocolService/PushSend",
+ FullMethod: "/weshnet.protocol.v1.ProtocolService/OutOfStoreReceive",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
- return srv.(ProtocolServiceServer).PushSend(ctx, req.(*PushSend_Request))
+ return srv.(ProtocolServiceServer).OutOfStoreReceive(ctx, req.(*OutOfStoreReceive_Request))
}
return interceptor(ctx, in, info, handler)
}
-func _ProtocolService_PushShareToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
- in := new(PushShareToken_Request)
+func _ProtocolService_OutOfStoreSeal_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(OutOfStoreSeal_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
- return srv.(ProtocolServiceServer).PushShareToken(ctx, in)
+ return srv.(ProtocolServiceServer).OutOfStoreSeal(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
- FullMethod: "/weshnet.protocol.v1.ProtocolService/PushShareToken",
+ FullMethod: "/weshnet.protocol.v1.ProtocolService/OutOfStoreSeal",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
- return srv.(ProtocolServiceServer).PushShareToken(ctx, req.(*PushShareToken_Request))
- }
- return interceptor(ctx, in, info, handler)
-}
-
-func _ProtocolService_PushSetDeviceToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
- in := new(PushSetDeviceToken_Request)
- if err := dec(in); err != nil {
- return nil, err
- }
- if interceptor == nil {
- return srv.(ProtocolServiceServer).PushSetDeviceToken(ctx, in)
- }
- info := &grpc.UnaryServerInfo{
- Server: srv,
- FullMethod: "/weshnet.protocol.v1.ProtocolService/PushSetDeviceToken",
- }
- handler := func(ctx context.Context, req interface{}) (interface{}, error) {
- return srv.(ProtocolServiceServer).PushSetDeviceToken(ctx, req.(*PushSetDeviceToken_Request))
- }
- return interceptor(ctx, in, info, handler)
-}
-
-func _ProtocolService_PushSetServer_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
- in := new(PushSetServer_Request)
- if err := dec(in); err != nil {
- return nil, err
- }
- if interceptor == nil {
- return srv.(ProtocolServiceServer).PushSetServer(ctx, in)
- }
- info := &grpc.UnaryServerInfo{
- Server: srv,
- FullMethod: "/weshnet.protocol.v1.ProtocolService/PushSetServer",
- }
- handler := func(ctx context.Context, req interface{}) (interface{}, error) {
- return srv.(ProtocolServiceServer).PushSetServer(ctx, req.(*PushSetServer_Request))
+ return srv.(ProtocolServiceServer).OutOfStoreSeal(ctx, req.(*OutOfStoreSeal_Request))
}
return interceptor(ctx, in, info, handler)
}
@@ -1912,24 +1810,12 @@ var ProtocolService_ServiceDesc = grpc.ServiceDesc{
Handler: _ProtocolService_PeerList_Handler,
},
{
- MethodName: "PushReceive",
- Handler: _ProtocolService_PushReceive_Handler,
- },
- {
- MethodName: "PushSend",
- Handler: _ProtocolService_PushSend_Handler,
- },
- {
- MethodName: "PushShareToken",
- Handler: _ProtocolService_PushShareToken_Handler,
- },
- {
- MethodName: "PushSetDeviceToken",
- Handler: _ProtocolService_PushSetDeviceToken_Handler,
+ MethodName: "OutOfStoreReceive",
+ Handler: _ProtocolService_OutOfStoreReceive_Handler,
},
{
- MethodName: "PushSetServer",
- Handler: _ProtocolService_PushSetServer_Handler,
+ MethodName: "OutOfStoreSeal",
+ Handler: _ProtocolService_OutOfStoreSeal_Handler,
},
{
MethodName: "RefreshContactRequest",
diff --git a/pkg/pushtypes/pushtypes.pb.go b/pkg/pushtypes/pushtypes.pb.go
index 7f8a5a60..d096d977 100644
--- a/pkg/pushtypes/pushtypes.pb.go
+++ b/pkg/pushtypes/pushtypes.pb.go
@@ -529,7 +529,7 @@ func (m *OutOfStoreMessageEnvelope) GetGroupReference() []byte {
return nil
}
-type PushExposedData struct {
+type OutOfStoreExposedData struct {
Nonce []byte `protobuf:"bytes,1,opt,name=nonce,proto3" json:"nonce,omitempty"`
Box []byte `protobuf:"bytes,2,opt,name=box,proto3" json:"box,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
@@ -537,18 +537,18 @@ type PushExposedData struct {
XXX_sizecache int32 `json:"-"`
}
-func (m *PushExposedData) Reset() { *m = PushExposedData{} }
-func (m *PushExposedData) String() string { return proto.CompactTextString(m) }
-func (*PushExposedData) ProtoMessage() {}
-func (*PushExposedData) Descriptor() ([]byte, []int) {
+func (m *OutOfStoreExposedData) Reset() { *m = OutOfStoreExposedData{} }
+func (m *OutOfStoreExposedData) String() string { return proto.CompactTextString(m) }
+func (*OutOfStoreExposedData) ProtoMessage() {}
+func (*OutOfStoreExposedData) Descriptor() ([]byte, []int) {
return fileDescriptor_6b0fb36a3e3f285e, []int{4}
}
-func (m *PushExposedData) XXX_Unmarshal(b []byte) error {
+func (m *OutOfStoreExposedData) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
-func (m *PushExposedData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+func (m *OutOfStoreExposedData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
- return xxx_messageInfo_PushExposedData.Marshal(b, m, deterministic)
+ return xxx_messageInfo_OutOfStoreExposedData.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
@@ -558,26 +558,26 @@ func (m *PushExposedData) XXX_Marshal(b []byte, deterministic bool) ([]byte, err
return b[:n], nil
}
}
-func (m *PushExposedData) XXX_Merge(src proto.Message) {
- xxx_messageInfo_PushExposedData.Merge(m, src)
+func (m *OutOfStoreExposedData) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_OutOfStoreExposedData.Merge(m, src)
}
-func (m *PushExposedData) XXX_Size() int {
+func (m *OutOfStoreExposedData) XXX_Size() int {
return m.Size()
}
-func (m *PushExposedData) XXX_DiscardUnknown() {
- xxx_messageInfo_PushExposedData.DiscardUnknown(m)
+func (m *OutOfStoreExposedData) XXX_DiscardUnknown() {
+ xxx_messageInfo_OutOfStoreExposedData.DiscardUnknown(m)
}
-var xxx_messageInfo_PushExposedData proto.InternalMessageInfo
+var xxx_messageInfo_OutOfStoreExposedData proto.InternalMessageInfo
-func (m *PushExposedData) GetNonce() []byte {
+func (m *OutOfStoreExposedData) GetNonce() []byte {
if m != nil {
return m.Nonce
}
return nil
}
-func (m *PushExposedData) GetBox() []byte {
+func (m *OutOfStoreExposedData) GetBox() []byte {
if m != nil {
return m.Box
}
@@ -897,7 +897,7 @@ func init() {
proto.RegisterType((*PushServiceSend_Request)(nil), "weshnet.push.v1.PushServiceSend.Request")
proto.RegisterType((*PushServiceSend_Reply)(nil), "weshnet.push.v1.PushServiceSend.Reply")
proto.RegisterType((*OutOfStoreMessageEnvelope)(nil), "weshnet.push.v1.OutOfStoreMessageEnvelope")
- proto.RegisterType((*PushExposedData)(nil), "weshnet.push.v1.PushExposedData")
+ proto.RegisterType((*OutOfStoreExposedData)(nil), "weshnet.push.v1.OutOfStoreExposedData")
proto.RegisterType((*PushServiceOpaqueReceiver)(nil), "weshnet.push.v1.PushServiceOpaqueReceiver")
proto.RegisterType((*DecryptedPush)(nil), "weshnet.push.v1.DecryptedPush")
proto.RegisterType((*FormatedPush)(nil), "weshnet.push.v1.FormatedPush")
@@ -906,83 +906,83 @@ func init() {
func init() { proto.RegisterFile("pushtypes/pushtypes.proto", fileDescriptor_6b0fb36a3e3f285e) }
var fileDescriptor_6b0fb36a3e3f285e = []byte{
- // 1211 bytes of a gzipped FileDescriptorProto
+ // 1213 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xcd, 0x6e, 0xdb, 0xc6,
- 0x16, 0x0e, 0xf5, 0x67, 0xea, 0xc8, 0x8e, 0xe8, 0xb1, 0x9c, 0xc8, 0x0a, 0x62, 0x3b, 0xcc, 0xcd,
- 0x8d, 0xe3, 0x9b, 0x2b, 0xe3, 0x3a, 0xc0, 0x2d, 0xda, 0x6e, 0x6a, 0x47, 0x49, 0xe3, 0x26, 0xfe,
- 0x29, 0xe3, 0xa0, 0x45, 0x81, 0x42, 0xa0, 0x34, 0xc7, 0x32, 0x63, 0x6a, 0x66, 0xc2, 0x1f, 0x3b,
- 0xec, 0xaa, 0xeb, 0x3e, 0x42, 0x5f, 0xa0, 0x28, 0xba, 0xe8, 0x6b, 0x74, 0x59, 0xa0, 0xeb, 0x1a,
- 0x85, 0x1e, 0xa3, 0x8b, 0xa2, 0x98, 0x19, 0x92, 0x92, 0xe2, 0xc4, 0x08, 0xba, 0xd2, 0x9c, 0xef,
- 0x7c, 0xe7, 0x47, 0x73, 0xbe, 0x03, 0x0e, 0x2c, 0x89, 0x38, 0x3c, 0x8e, 0x12, 0x81, 0xe1, 0x46,
- 0x7e, 0x6a, 0x8b, 0x80, 0x47, 0x9c, 0xd4, 0xcf, 0x30, 0x3c, 0x66, 0x18, 0xb5, 0xa5, 0xa3, 0x7d,
- 0xfa, 0xbf, 0x56, 0x63, 0xc0, 0x07, 0x5c, 0xf9, 0x36, 0xe4, 0x49, 0xd3, 0xec, 0x9f, 0x0d, 0x58,
- 0x3c, 0x88, 0xc3, 0xe3, 0xe7, 0x18, 0x9c, 0x7a, 0x7d, 0x94, 0x3f, 0x18, 0xec, 0xb0, 0x23, 0xde,
- 0xaa, 0xc2, 0x8c, 0x83, 0xaf, 0x62, 0x0c, 0xa3, 0xd6, 0x77, 0x06, 0x94, 0x1d, 0x14, 0x7e, 0x42,
- 0x6e, 0x02, 0x88, 0xb8, 0xe7, 0x7b, 0xfd, 0xee, 0x09, 0x26, 0x4d, 0x63, 0xd5, 0x58, 0x9b, 0x75,
- 0xaa, 0x1a, 0x79, 0x8a, 0x09, 0xe9, 0xc1, 0x62, 0x18, 0x0b, 0xc1, 0x83, 0x08, 0x69, 0x37, 0xe2,
- 0x27, 0xc8, 0xba, 0xaa, 0xa7, 0x66, 0x61, 0xb5, 0xb8, 0x56, 0xdb, 0x6c, 0xb7, 0xdf, 0x68, 0xaa,
- 0x3d, 0x59, 0x3a, 0x0b, 0x3c, 0x94, 0x71, 0x87, 0x89, 0x40, 0x67, 0x21, 0xbc, 0x80, 0x85, 0xf6,
- 0xf7, 0x06, 0xdc, 0xbc, 0x34, 0x8c, 0x3c, 0x80, 0x39, 0x57, 0x88, 0x6e, 0x2f, 0x66, 0xd4, 0xc7,
- 0xae, 0x47, 0x55, 0x9f, 0xd5, 0xed, 0xfa, 0xe8, 0x7c, 0xa5, 0xb6, 0x25, 0xc4, 0xb6, 0xc2, 0x77,
- 0x3a, 0x4e, 0xcd, 0xcd, 0x0d, 0x4a, 0x3a, 0x00, 0xe3, 0x86, 0x9b, 0x85, 0x55, 0x63, 0xed, 0xea,
- 0xe6, 0x9d, 0xcb, 0xfa, 0x1d, 0xb7, 0x59, 0x8d, 0xb2, 0xa3, 0xfd, 0xa7, 0x01, 0xf5, 0xa9, 0xeb,
- 0x64, 0xb4, 0xf5, 0xbb, 0x91, 0xdf, 0x24, 0x79, 0x0c, 0x26, 0xb2, 0x53, 0xf4, 0xb9, 0x40, 0xd5,
- 0x55, 0x6d, 0x73, 0xfd, 0x42, 0x8d, 0xfd, 0x38, 0xda, 0x3f, 0x7a, 0x1e, 0xf1, 0x00, 0x77, 0x31,
- 0x0c, 0xdd, 0x01, 0x3e, 0x4a, 0x23, 0x9c, 0x3c, 0x96, 0x7c, 0x02, 0xa6, 0x08, 0x3c, 0x1e, 0x78,
- 0x51, 0x92, 0xf6, 0xfa, 0xaf, 0xcb, 0x7a, 0x3d, 0x48, 0xb9, 0x4e, 0x1e, 0x45, 0x9e, 0x40, 0x35,
- 0xc0, 0x3e, 0x7a, 0xa7, 0x18, 0x84, 0xcd, 0xa2, 0x1a, 0xcf, 0xfa, 0x65, 0x29, 0xf6, 0x85, 0xfb,
- 0x2a, 0x46, 0x27, 0x0d, 0x71, 0xc6, 0xc1, 0xad, 0x99, 0x54, 0x1c, 0xf6, 0xb7, 0x06, 0x2c, 0xbd,
- 0xb3, 0x79, 0xd2, 0x80, 0x32, 0xe3, 0xac, 0x8f, 0xa9, 0x6a, 0xb4, 0x41, 0x2c, 0x28, 0xf6, 0xf8,
- 0x6b, 0xf5, 0x1f, 0x66, 0x1d, 0x79, 0x24, 0x1f, 0x43, 0x7d, 0x10, 0xf0, 0x58, 0x74, 0x03, 0x3c,
- 0xc2, 0x00, 0x65, 0x44, 0x49, 0x7a, 0xb7, 0xc9, 0xe8, 0x7c, 0xe5, 0xea, 0xa7, 0xd2, 0xe5, 0x64,
- 0x1e, 0xe7, 0xea, 0x60, 0xca, 0xb6, 0x3f, 0xd4, 0xd7, 0xff, 0xe8, 0xb5, 0xe0, 0x21, 0xd2, 0x8e,
- 0x1b, 0xb9, 0xef, 0x5b, 0xd7, 0x76, 0x61, 0xe9, 0x9d, 0x7f, 0x97, 0xdc, 0x82, 0x59, 0xae, 0x10,
- 0xad, 0xea, 0x34, 0x57, 0x4d, 0x63, 0x4a, 0x09, 0x92, 0x12, 0xea, 0xd8, 0xae, 0x4b, 0x69, 0xa0,
- 0x52, 0x57, 0x9d, 0x5a, 0x8a, 0x6d, 0x51, 0x1a, 0xd8, 0x3f, 0x54, 0x60, 0xae, 0x83, 0xfd, 0x20,
- 0x11, 0x11, 0x52, 0x59, 0x8c, 0xdc, 0x07, 0x70, 0xfb, 0x7d, 0x1e, 0xb3, 0x68, 0xac, 0xd3, 0xb9,
- 0xd1, 0xf9, 0x4a, 0x75, 0x4b, 0xa3, 0x3b, 0x1d, 0xa7, 0x9a, 0x12, 0x76, 0xa8, 0x2c, 0x91, 0xb1,
- 0x99, 0x3b, 0xc4, 0xac, 0x44, 0x8a, 0xed, 0xb9, 0x43, 0x24, 0xff, 0x87, 0xeb, 0x7d, 0xce, 0xe4,
- 0x5c, 0xdc, 0xc8, 0xe3, 0xac, 0x3b, 0xb1, 0xad, 0x45, 0xc5, 0x5e, 0x9c, 0x74, 0x1f, 0xe4, 0x9b,
- 0xfb, 0x11, 0x2c, 0x4d, 0xc5, 0x51, 0x2f, 0x14, 0xbe, 0x9b, 0xe8, 0x3a, 0x25, 0x15, 0x39, 0x95,
- 0xb8, 0xa3, 0xfd, 0xaa, 0xe6, 0x3a, 0xcc, 0x0f, 0x71, 0xd8, 0xc3, 0x60, 0xb2, 0x5a, 0x59, 0xc5,
- 0xd4, 0xb5, 0x63, 0x5c, 0xa7, 0x0d, 0x0b, 0x29, 0x77, 0xaa, 0x42, 0x45, 0xb1, 0xd3, 0x34, 0x93,
- 0xb9, 0x3b, 0x50, 0x95, 0x62, 0xd4, 0x5b, 0x39, 0xa3, 0x94, 0x7e, 0xf7, 0x82, 0x4c, 0xa7, 0xee,
- 0x54, 0x89, 0x56, 0xed, 0xa5, 0x29, 0xd2, 0x13, 0xd9, 0x06, 0x22, 0xdc, 0xc4, 0xe7, 0x2e, 0xed,
- 0xba, 0x51, 0x14, 0x84, 0xdd, 0x97, 0x21, 0x67, 0x4d, 0x53, 0x5d, 0x77, 0x63, 0x74, 0xbe, 0x62,
- 0x1d, 0x68, 0xef, 0x96, 0x74, 0x7e, 0xf6, 0x7c, 0x7f, 0xcf, 0xb1, 0xc4, 0x24, 0x12, 0x72, 0x46,
- 0x6e, 0x40, 0x95, 0x22, 0x8a, 0xae, 0xef, 0xb1, 0x93, 0x66, 0x55, 0xf5, 0x6b, 0x4a, 0xe0, 0x99,
- 0xc7, 0x4e, 0xc8, 0x3d, 0xb0, 0x5c, 0x3f, 0x40, 0x97, 0x26, 0xdd, 0x74, 0x31, 0x68, 0x13, 0x56,
- 0x8d, 0x35, 0xd3, 0xa9, 0xa7, 0x78, 0x2a, 0x25, 0x4a, 0x6e, 0xc3, 0x5c, 0x36, 0xc4, 0x61, 0x1c,
- 0x21, 0x6d, 0xd6, 0x14, 0x2f, 0x9b, 0xec, 0xae, 0xc4, 0xc8, 0x7f, 0x81, 0x4c, 0x8d, 0x43, 0x33,
- 0x67, 0x15, 0x73, 0x7e, 0xd2, 0xa3, 0xe9, 0xb7, 0x60, 0xf6, 0xd8, 0xa3, 0xd8, 0x15, 0x01, 0x9e,
- 0x7a, 0x78, 0xd6, 0x9c, 0x53, 0xc4, 0x9a, 0xc4, 0x0e, 0x34, 0x64, 0xff, 0x64, 0x80, 0x99, 0xdd,
- 0x0c, 0xa9, 0xc1, 0xcc, 0x0b, 0x76, 0xc2, 0xf8, 0x19, 0xb3, 0xae, 0x48, 0x23, 0xdd, 0x55, 0xcb,
- 0x20, 0x0b, 0x50, 0x57, 0x2b, 0xb6, 0xc3, 0x4e, 0xbd, 0x48, 0x55, 0xb0, 0x66, 0xc8, 0x0d, 0xb8,
- 0xfe, 0x70, 0xa2, 0xa6, 0x1c, 0xcc, 0xc3, 0x63, 0x97, 0x0d, 0x90, 0x5a, 0x26, 0x59, 0x84, 0xf9,
- 0x5d, 0x35, 0xb6, 0x49, 0xb8, 0x4a, 0x9a, 0xd0, 0xd0, 0x70, 0x07, 0x23, 0xd7, 0xf3, 0xc3, 0xcc,
- 0x53, 0xb3, 0x4b, 0x66, 0xc1, 0x2a, 0xd8, 0x25, 0xb3, 0x68, 0x15, 0xed, 0x92, 0x59, 0xb2, 0x4a,
- 0x76, 0xc9, 0x2c, 0x5b, 0x65, 0xbb, 0x64, 0x56, 0xac, 0x8a, 0x5d, 0x32, 0xc1, 0x02, 0xfb, 0xc7,
- 0x02, 0xcc, 0x3e, 0xe6, 0xc1, 0xd0, 0xcd, 0x16, 0x65, 0x4a, 0x07, 0xc6, 0x3f, 0xd5, 0x41, 0x03,
- 0xca, 0x91, 0x17, 0xf9, 0xd9, 0xe6, 0x68, 0x83, 0xb4, 0xc0, 0x0c, 0xe3, 0x9e, 0x76, 0xe8, 0x25,
- 0xc9, 0x6d, 0x42, 0xa0, 0xd4, 0xe3, 0x34, 0x49, 0x57, 0x40, 0x9d, 0xa7, 0x95, 0x50, 0x7e, 0x43,
- 0x09, 0x0d, 0x28, 0xeb, 0x61, 0x55, 0xd4, 0x0c, 0xb4, 0x71, 0x61, 0x40, 0x33, 0x17, 0x06, 0x44,
- 0x3e, 0x78, 0x63, 0x73, 0x3d, 0x8a, 0x2c, 0xf2, 0x8e, 0x3c, 0x0c, 0xb4, 0x50, 0x9d, 0x6b, 0x93,
- 0xee, 0x9d, 0xdc, 0xbb, 0xfe, 0x97, 0x01, 0x8d, 0xb7, 0x7d, 0x97, 0xc8, 0x35, 0x20, 0xea, 0x0e,
- 0x24, 0xf0, 0x82, 0x51, 0x3c, 0xf2, 0x18, 0x52, 0xeb, 0x0a, 0x99, 0x87, 0xb9, 0x1c, 0xdf, 0xfd,
- 0xfc, 0xf0, 0xd0, 0x32, 0xc8, 0x3d, 0xb8, 0x93, 0x43, 0x5b, 0x42, 0xf8, 0x28, 0xad, 0x3d, 0x2e,
- 0x2b, 0xf4, 0x55, 0xbd, 0x34, 0xb9, 0x55, 0x20, 0xb7, 0x61, 0x25, 0xa7, 0x3e, 0xf6, 0x02, 0xec,
- 0xb9, 0x21, 0x3e, 0xf4, 0x79, 0x4c, 0xb5, 0x88, 0x3c, 0x36, 0xb0, 0x8a, 0xe4, 0x3f, 0x70, 0x37,
- 0x27, 0x7d, 0xe1, 0x31, 0xca, 0xcf, 0xc2, 0x77, 0x65, 0x2c, 0x91, 0x16, 0x5c, 0xcb, 0xc9, 0x4f,
- 0x62, 0xf7, 0x0c, 0x3d, 0x69, 0x3e, 0xf5, 0x22, 0xab, 0x4c, 0x6c, 0x58, 0x1e, 0x37, 0x36, 0x74,
- 0xbf, 0xe1, 0xac, 0x83, 0x32, 0x6c, 0x5c, 0xac, 0xb2, 0xfe, 0x35, 0x2c, 0xbc, 0xe5, 0x5b, 0x47,
- 0x96, 0xf4, 0xcb, 0x26, 0xb3, 0x27, 0x6f, 0x60, 0x41, 0x7f, 0x26, 0x32, 0xd7, 0x33, 0x7e, 0x66,
- 0x19, 0xd9, 0x75, 0x65, 0xe0, 0x9e, 0x94, 0x9f, 0x6f, 0x15, 0x36, 0x7f, 0x33, 0xa0, 0x36, 0x91,
- 0x9f, 0xbc, 0x04, 0x18, 0x3f, 0x93, 0xc8, 0xe5, 0x6f, 0x9a, 0x9c, 0xd7, 0xce, 0xde, 0x52, 0xf7,
- 0xdf, 0x9b, 0x2f, 0xdf, 0x5b, 0x5f, 0x42, 0x49, 0xbe, 0x21, 0xc8, 0xda, 0xe5, 0x51, 0x8c, 0xe6,
- 0xf9, 0xff, 0xfd, 0x1e, 0x4c, 0xe1, 0x27, 0xdb, 0xed, 0x5f, 0x46, 0xcb, 0xc6, 0xaf, 0xa3, 0x65,
- 0xe3, 0x8f, 0xd1, 0xb2, 0xf1, 0xd5, 0x6a, 0x0f, 0x83, 0x28, 0x69, 0x47, 0xd8, 0x3f, 0xde, 0x48,
- 0xe3, 0x37, 0xc4, 0xc9, 0x60, 0xfc, 0xaa, 0xec, 0x55, 0xd4, 0x7b, 0xf1, 0xc1, 0xdf, 0x01, 0x00,
- 0x00, 0xff, 0xff, 0x49, 0x51, 0xb6, 0x09, 0x73, 0x0a, 0x00, 0x00,
+ 0x16, 0x0e, 0x25, 0x4a, 0xa6, 0x8e, 0xec, 0x88, 0x1e, 0xcb, 0x89, 0xac, 0x20, 0xb6, 0xc3, 0xdc,
+ 0xdc, 0x38, 0xbe, 0xb9, 0x32, 0xae, 0x03, 0xdc, 0x02, 0xed, 0xa2, 0xb5, 0xa3, 0xa4, 0x71, 0x13,
+ 0xff, 0x94, 0x71, 0xd0, 0xa2, 0x40, 0x41, 0x50, 0x9a, 0x63, 0x99, 0x31, 0x35, 0x33, 0xe1, 0x8f,
+ 0x1d, 0x76, 0xd5, 0x75, 0x1f, 0xa1, 0x2f, 0x50, 0x14, 0x5d, 0xf4, 0x35, 0xba, 0x2c, 0xd0, 0x75,
+ 0x8d, 0x42, 0x8f, 0xd1, 0x45, 0x51, 0xcc, 0xf0, 0x47, 0x52, 0x9c, 0x18, 0x41, 0x57, 0x9a, 0xf3,
+ 0x9d, 0xef, 0xfc, 0x68, 0xce, 0x77, 0xc0, 0x81, 0x25, 0x11, 0x87, 0xc7, 0x51, 0x22, 0x30, 0xdc,
+ 0x28, 0x4e, 0x1d, 0x11, 0xf0, 0x88, 0x93, 0xc6, 0x19, 0x86, 0xc7, 0x0c, 0xa3, 0x8e, 0x74, 0x74,
+ 0x4e, 0xff, 0xd7, 0x6e, 0x0e, 0xf8, 0x80, 0x2b, 0xdf, 0x86, 0x3c, 0xa5, 0x34, 0xeb, 0x67, 0x0d,
+ 0x16, 0x0f, 0xe2, 0xf0, 0xf8, 0x39, 0x06, 0xa7, 0x5e, 0x1f, 0xe5, 0x0f, 0x06, 0x3b, 0xec, 0x88,
+ 0xb7, 0x6b, 0x30, 0x63, 0xe3, 0xab, 0x18, 0xc3, 0xa8, 0xfd, 0x9d, 0x06, 0x15, 0x1b, 0x85, 0x9f,
+ 0x90, 0x9b, 0x00, 0x22, 0xee, 0xf9, 0x5e, 0xdf, 0x39, 0xc1, 0xa4, 0xa5, 0xad, 0x6a, 0x6b, 0xb3,
+ 0x76, 0x2d, 0x45, 0x9e, 0x62, 0x42, 0x7a, 0xb0, 0x18, 0xc6, 0x42, 0xf0, 0x20, 0x42, 0xea, 0x44,
+ 0xfc, 0x04, 0x99, 0xa3, 0x7a, 0x6a, 0x95, 0x56, 0xcb, 0x6b, 0xf5, 0xcd, 0x4e, 0xe7, 0x8d, 0xa6,
+ 0x3a, 0x93, 0xa5, 0xf3, 0xc0, 0x43, 0x19, 0x77, 0x98, 0x08, 0xb4, 0x17, 0xc2, 0x0b, 0x58, 0x68,
+ 0x7d, 0xaf, 0xc1, 0xcd, 0x4b, 0xc3, 0xc8, 0x03, 0x98, 0x73, 0x85, 0x70, 0x7a, 0x31, 0xa3, 0x3e,
+ 0x3a, 0x1e, 0x55, 0x7d, 0xd6, 0xb6, 0x1b, 0xa3, 0xf3, 0x95, 0xfa, 0x96, 0x10, 0xdb, 0x0a, 0xdf,
+ 0xe9, 0xda, 0x75, 0xb7, 0x30, 0x28, 0xe9, 0x02, 0x8c, 0x1b, 0x6e, 0x95, 0x56, 0xb5, 0xb5, 0xab,
+ 0x9b, 0x77, 0x2e, 0xeb, 0x77, 0xdc, 0x66, 0x2d, 0xca, 0x8f, 0xd6, 0x9f, 0x1a, 0x34, 0xa6, 0xae,
+ 0x93, 0xd1, 0xf6, 0xef, 0x5a, 0x71, 0x93, 0xe4, 0x31, 0x18, 0xc8, 0x4e, 0xd1, 0xe7, 0x02, 0x55,
+ 0x57, 0xf5, 0xcd, 0xf5, 0x0b, 0x35, 0xf6, 0xe3, 0x68, 0xff, 0xe8, 0x79, 0xc4, 0x03, 0xdc, 0xc5,
+ 0x30, 0x74, 0x07, 0xf8, 0x28, 0x8b, 0xb0, 0x8b, 0x58, 0xf2, 0x09, 0x18, 0x22, 0xf0, 0x78, 0xe0,
+ 0x45, 0x49, 0xd6, 0xeb, 0xbf, 0x2e, 0xeb, 0xf5, 0x20, 0xe3, 0xda, 0x45, 0x14, 0x79, 0x02, 0xb5,
+ 0x00, 0xfb, 0xe8, 0x9d, 0x62, 0x10, 0xb6, 0xca, 0x6a, 0x3c, 0xeb, 0x97, 0xa5, 0xd8, 0x17, 0xee,
+ 0xab, 0x18, 0xed, 0x2c, 0xc4, 0x1e, 0x07, 0xb7, 0x67, 0x32, 0x71, 0x58, 0xdf, 0x6a, 0xb0, 0xf4,
+ 0xce, 0xe6, 0x49, 0x13, 0x2a, 0x8c, 0xb3, 0x3e, 0x66, 0xaa, 0x49, 0x0d, 0x62, 0x42, 0xb9, 0xc7,
+ 0x5f, 0xab, 0xff, 0x30, 0x6b, 0xcb, 0x23, 0xf9, 0x08, 0x1a, 0x83, 0x80, 0xc7, 0xc2, 0x09, 0xf0,
+ 0x08, 0x03, 0x94, 0x11, 0xba, 0xf4, 0x6e, 0x93, 0xd1, 0xf9, 0xca, 0xd5, 0x4f, 0xa5, 0xcb, 0xce,
+ 0x3d, 0xf6, 0xd5, 0xc1, 0x94, 0x6d, 0x7d, 0x0c, 0x8b, 0xe3, 0x0e, 0x1e, 0xbd, 0x16, 0x3c, 0x44,
+ 0xda, 0x75, 0x23, 0xf7, 0x7d, 0xab, 0x5b, 0x2e, 0x2c, 0xbd, 0xf3, 0x4f, 0x93, 0x5b, 0x30, 0xcb,
+ 0x15, 0x92, 0x6a, 0x3b, 0xcb, 0x55, 0x4f, 0x31, 0xa5, 0x07, 0x49, 0x09, 0xd3, 0x58, 0xc7, 0xa5,
+ 0x34, 0x50, 0xa9, 0x6b, 0x76, 0x3d, 0xc3, 0xb6, 0x28, 0x0d, 0xac, 0x1f, 0xaa, 0x30, 0xd7, 0xc5,
+ 0x7e, 0x90, 0x88, 0x08, 0xa9, 0x2c, 0x46, 0xee, 0x03, 0xb8, 0xfd, 0x3e, 0x8f, 0x59, 0x34, 0x56,
+ 0xeb, 0xdc, 0xe8, 0x7c, 0xa5, 0xb6, 0x95, 0xa2, 0x3b, 0x5d, 0xbb, 0x96, 0x11, 0x76, 0xa8, 0x2c,
+ 0x91, 0xb3, 0x99, 0x3b, 0xc4, 0xbc, 0x44, 0x86, 0xed, 0xb9, 0x43, 0x24, 0xff, 0x87, 0xeb, 0x7d,
+ 0xce, 0xe4, 0x74, 0xdc, 0xc8, 0xe3, 0xcc, 0x99, 0xd8, 0xd9, 0xb2, 0x62, 0x2f, 0x4e, 0xba, 0x0f,
+ 0x8a, 0xfd, 0xfd, 0x10, 0x96, 0xa6, 0xe2, 0xa8, 0x17, 0x0a, 0xdf, 0x4d, 0xd2, 0x3a, 0xba, 0x8a,
+ 0x9c, 0x4a, 0xdc, 0x4d, 0xfd, 0xaa, 0xe6, 0x3a, 0xcc, 0x0f, 0x71, 0xd8, 0xc3, 0x60, 0xb2, 0x5a,
+ 0x45, 0xc5, 0x34, 0x52, 0xc7, 0xb8, 0x4e, 0x07, 0x16, 0x32, 0xee, 0x54, 0x85, 0xaa, 0x62, 0x67,
+ 0x69, 0x26, 0x73, 0x77, 0xa1, 0x26, 0x25, 0x99, 0xee, 0xe6, 0x8c, 0xd2, 0xfb, 0xdd, 0x0b, 0x62,
+ 0x9d, 0xba, 0x53, 0x25, 0x5d, 0xb5, 0x9d, 0x86, 0xc8, 0x4e, 0x64, 0x1b, 0x88, 0x70, 0x13, 0x9f,
+ 0xbb, 0xd4, 0x71, 0xa3, 0x28, 0x08, 0x9d, 0x97, 0x21, 0x67, 0x2d, 0x43, 0x5d, 0x77, 0x73, 0x74,
+ 0xbe, 0x62, 0x1e, 0xa4, 0xde, 0x2d, 0xe9, 0xfc, 0xec, 0xf9, 0xfe, 0x9e, 0x6d, 0x8a, 0x49, 0x24,
+ 0xe4, 0x8c, 0xdc, 0x80, 0x1a, 0x45, 0x14, 0x8e, 0xef, 0xb1, 0x93, 0x56, 0x4d, 0xf5, 0x6b, 0x48,
+ 0xe0, 0x99, 0xc7, 0x4e, 0xc8, 0x3d, 0x30, 0x5d, 0x3f, 0x40, 0x97, 0x26, 0x4e, 0xb6, 0x1e, 0xb4,
+ 0x05, 0xab, 0xda, 0x9a, 0x61, 0x37, 0x32, 0x3c, 0x93, 0x12, 0x25, 0xb7, 0x61, 0x2e, 0x1f, 0xe2,
+ 0x30, 0x8e, 0x90, 0xb6, 0xea, 0x8a, 0x97, 0x4f, 0x76, 0x57, 0x62, 0xe4, 0xbf, 0x40, 0xa6, 0xc6,
+ 0x91, 0x32, 0x67, 0x15, 0x73, 0x7e, 0xd2, 0x93, 0xd2, 0x6f, 0xc1, 0xec, 0xb1, 0x47, 0xd1, 0x11,
+ 0x01, 0x9e, 0x7a, 0x78, 0xd6, 0x9a, 0x53, 0xc4, 0xba, 0xc4, 0x0e, 0x52, 0xc8, 0xfa, 0x49, 0x03,
+ 0x23, 0xbf, 0x19, 0x52, 0x87, 0x99, 0x17, 0xec, 0x84, 0xf1, 0x33, 0x66, 0x5e, 0x91, 0x46, 0xb6,
+ 0xb1, 0xa6, 0x46, 0x16, 0xa0, 0xa1, 0x16, 0x6d, 0x87, 0x9d, 0x7a, 0x91, 0xaa, 0x60, 0xce, 0x90,
+ 0x1b, 0x70, 0xfd, 0xe1, 0x44, 0x4d, 0x39, 0x98, 0x87, 0xc7, 0x2e, 0x1b, 0x20, 0x35, 0x0d, 0xb2,
+ 0x08, 0xf3, 0xbb, 0x6a, 0x6c, 0x93, 0x70, 0x8d, 0xb4, 0xa0, 0x99, 0xc2, 0x5d, 0x8c, 0x5c, 0xcf,
+ 0x0f, 0x73, 0x4f, 0xdd, 0xd2, 0x8d, 0x92, 0x59, 0xb2, 0x74, 0xa3, 0x6c, 0x96, 0x2d, 0xdd, 0xd0,
+ 0x4d, 0xdd, 0xd2, 0x8d, 0x8a, 0x59, 0xb1, 0x74, 0xa3, 0x6a, 0x56, 0x2d, 0xdd, 0x00, 0x13, 0xac,
+ 0x1f, 0x4b, 0x30, 0xfb, 0x98, 0x07, 0x43, 0x37, 0x5f, 0x94, 0x29, 0x1d, 0x68, 0xff, 0x54, 0x07,
+ 0x4d, 0xa8, 0x44, 0x5e, 0xe4, 0xe7, 0x9b, 0x93, 0x1a, 0xa4, 0x0d, 0x46, 0x18, 0xf7, 0x52, 0x47,
+ 0xba, 0x24, 0x85, 0x4d, 0x08, 0xe8, 0x3d, 0x4e, 0x93, 0x6c, 0x05, 0xd4, 0x79, 0x5a, 0x09, 0x95,
+ 0x37, 0x94, 0xd0, 0x84, 0x4a, 0x3a, 0xac, 0xaa, 0x9a, 0x41, 0x6a, 0x5c, 0x18, 0xd0, 0xcc, 0x85,
+ 0x01, 0x91, 0x0f, 0xde, 0xd8, 0x5c, 0x8f, 0x22, 0x8b, 0xbc, 0x23, 0x0f, 0x83, 0x54, 0xa8, 0xf6,
+ 0xb5, 0x49, 0xf7, 0x4e, 0xe1, 0x5d, 0xff, 0x4b, 0x83, 0xe6, 0xdb, 0xbe, 0x4e, 0xe4, 0x1a, 0x10,
+ 0x75, 0x07, 0x12, 0x78, 0xc1, 0x28, 0x1e, 0x79, 0x0c, 0xa9, 0x79, 0x85, 0xcc, 0xc3, 0x5c, 0x81,
+ 0xef, 0x7e, 0x7e, 0x78, 0x68, 0x6a, 0xe4, 0x1e, 0xdc, 0x29, 0xa0, 0x2d, 0x21, 0x7c, 0x94, 0xd6,
+ 0x1e, 0x97, 0x15, 0xfa, 0xaa, 0x5e, 0x96, 0xdc, 0x2c, 0x91, 0xdb, 0xb0, 0x52, 0x50, 0x1f, 0x7b,
+ 0x01, 0xf6, 0xdc, 0x10, 0x1f, 0xfa, 0x3c, 0xa6, 0xa9, 0x88, 0x3c, 0x36, 0x30, 0xcb, 0xe4, 0x3f,
+ 0x70, 0xb7, 0x20, 0x7d, 0xe1, 0x31, 0xca, 0xcf, 0xc2, 0x77, 0x65, 0xd4, 0x49, 0x1b, 0xae, 0x15,
+ 0xe4, 0x27, 0xb1, 0x7b, 0x86, 0x9e, 0x34, 0x9f, 0x7a, 0x91, 0x59, 0x21, 0x16, 0x2c, 0x8f, 0x1b,
+ 0x1b, 0xba, 0xdf, 0x70, 0xd6, 0x45, 0x19, 0x36, 0x2e, 0x56, 0x5d, 0xff, 0x1a, 0x16, 0xde, 0xf2,
+ 0xc5, 0x23, 0x4b, 0xe9, 0xfb, 0x26, 0xb7, 0x27, 0x6f, 0x60, 0x21, 0xfd, 0x56, 0xe7, 0xae, 0x67,
+ 0xfc, 0xcc, 0xd4, 0xf2, 0xeb, 0xca, 0xc1, 0x3d, 0x29, 0x3f, 0xdf, 0x2c, 0x6d, 0xfe, 0xa6, 0x41,
+ 0x7d, 0x22, 0x3f, 0x79, 0x09, 0x30, 0x7e, 0x2c, 0x91, 0xcb, 0x5f, 0x36, 0x05, 0xaf, 0x93, 0xbf,
+ 0xa8, 0xee, 0xbf, 0x37, 0x5f, 0xbe, 0xba, 0xbe, 0x04, 0x5d, 0xbe, 0x24, 0xc8, 0xda, 0xe5, 0x51,
+ 0x8c, 0x16, 0xf9, 0xff, 0xfd, 0x1e, 0x4c, 0xe1, 0x27, 0xdb, 0x9d, 0x5f, 0x46, 0xcb, 0xda, 0xaf,
+ 0xa3, 0x65, 0xed, 0x8f, 0xd1, 0xb2, 0xf6, 0xd5, 0x6a, 0x0f, 0x83, 0x28, 0xe9, 0x44, 0xd8, 0x3f,
+ 0xde, 0xc8, 0xe2, 0x37, 0xc4, 0xc9, 0x60, 0xfc, 0xb6, 0xec, 0x55, 0xd5, 0xab, 0xf1, 0xc1, 0xdf,
+ 0x01, 0x00, 0x00, 0xff, 0xff, 0x23, 0xe0, 0x7f, 0x2c, 0x79, 0x0a, 0x00, 0x00,
}
func (m *PushServiceServerInfo) Marshal() (dAtA []byte, err error) {
@@ -1286,7 +1286,7 @@ func (m *OutOfStoreMessageEnvelope) MarshalToSizedBuffer(dAtA []byte) (int, erro
return len(dAtA) - i, nil
}
-func (m *PushExposedData) Marshal() (dAtA []byte, err error) {
+func (m *OutOfStoreExposedData) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
@@ -1296,12 +1296,12 @@ func (m *PushExposedData) Marshal() (dAtA []byte, err error) {
return dAtA[:n], nil
}
-func (m *PushExposedData) MarshalTo(dAtA []byte) (int, error) {
+func (m *OutOfStoreExposedData) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
-func (m *PushExposedData) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+func (m *OutOfStoreExposedData) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
@@ -1732,7 +1732,7 @@ func (m *OutOfStoreMessageEnvelope) Size() (n int) {
return n
}
-func (m *PushExposedData) Size() (n int) {
+func (m *OutOfStoreExposedData) Size() (n int) {
if m == nil {
return 0
}
@@ -2596,7 +2596,7 @@ func (m *OutOfStoreMessageEnvelope) Unmarshal(dAtA []byte) error {
}
return nil
}
-func (m *PushExposedData) Unmarshal(dAtA []byte) error {
+func (m *OutOfStoreExposedData) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
@@ -2619,10 +2619,10 @@ func (m *PushExposedData) Unmarshal(dAtA []byte) error {
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
- return fmt.Errorf("proto: PushExposedData: wiretype end group for non-group")
+ return fmt.Errorf("proto: OutOfStoreExposedData: wiretype end group for non-group")
}
if fieldNum <= 0 {
- return fmt.Errorf("proto: PushExposedData: illegal tag %d (wire type %d)", fieldNum, wire)
+ return fmt.Errorf("proto: OutOfStoreExposedData: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
diff --git a/pkg/secretstore/chain_key.go b/pkg/secretstore/chain_key.go
new file mode 100644
index 00000000..58d3f348
--- /dev/null
+++ b/pkg/secretstore/chain_key.go
@@ -0,0 +1,87 @@
+package secretstore
+
+import (
+ crand "crypto/rand"
+ "fmt"
+
+ "github.com/libp2p/go-libp2p/core/crypto"
+ "golang.org/x/crypto/nacl/box"
+
+ "berty.tech/weshnet/pkg/cryptoutil"
+ "berty.tech/weshnet/pkg/errcode"
+ "berty.tech/weshnet/pkg/protocoltypes"
+)
+
+// newDeviceChainKey creates a new random chain key
+func newDeviceChainKey() (*protocoltypes.DeviceChainKey, error) {
+ chainKey := make([]byte, 32)
+ _, err := crand.Read(chainKey)
+ if err != nil {
+ return nil, errcode.ErrCryptoRandomGeneration.Wrap(err)
+ }
+
+ return &protocoltypes.DeviceChainKey{
+ ChainKey: chainKey,
+ Counter: 0,
+ }, nil
+}
+
+// encryptDeviceChainKey encrypts a device chain key for a target member
+func encryptDeviceChainKey(localDevicePrivateKey crypto.PrivKey, remoteMemberPubKey crypto.PubKey, deviceChainKey *protocoltypes.DeviceChainKey, group *protocoltypes.Group) ([]byte, error) {
+ chainKeyBytes, err := deviceChainKey.Marshal()
+ if err != nil {
+ return nil, errcode.ErrSerialization.Wrap(err)
+ }
+
+ mongPriv, mongPub, err := cryptoutil.EdwardsToMontgomery(localDevicePrivateKey, remoteMemberPubKey)
+ if err != nil {
+ return nil, errcode.ErrCryptoKeyConversion.Wrap(err)
+ }
+
+ nonce := groupIDToNonce(group)
+ encryptedChainKey := box.Seal(nil, chainKeyBytes, nonce, mongPub, mongPriv)
+
+ return encryptedChainKey, nil
+}
+
+// decryptDeviceChainKey decrypts a chain key sent by the given device
+func decryptDeviceChainKey(encryptedDeviceChainKey []byte, group *protocoltypes.Group, localMemberPrivateKey crypto.PrivKey, senderDevicePubKey crypto.PubKey) (*protocoltypes.DeviceChainKey, error) {
+ mongPriv, mongPub, err := cryptoutil.EdwardsToMontgomery(localMemberPrivateKey, senderDevicePubKey)
+ if err != nil {
+ return nil, errcode.ErrCryptoKeyConversion.Wrap(err)
+ }
+
+ nonce := groupIDToNonce(group)
+ decryptedSecret := &protocoltypes.DeviceChainKey{}
+ decryptedMessage, ok := box.Open(nil, encryptedDeviceChainKey, nonce, mongPub, mongPriv)
+ if !ok {
+ return nil, errcode.ErrCryptoDecrypt.Wrap(fmt.Errorf("unable to decrypt message"))
+ }
+
+ err = decryptedSecret.Unmarshal(decryptedMessage)
+ if err != nil {
+ return nil, errcode.ErrDeserialization.Wrap(err)
+ }
+
+ return decryptedSecret, nil
+}
+
+// groupIDToNonce converts a group public key to a value which can be used as
+// a nonce of the nacl library
+func groupIDToNonce(group *protocoltypes.Group) *[cryptoutil.NonceSize]byte {
+ // Nonce doesn't need to be secret, random nor unpredictable, it just needs
+ // to be used only once for a given sender+receiver set, and we will send
+ // only one SecretEntryPayload per localDevicePrivateKey+remoteMemberPubKey
+ // So we can reuse groupID as nonce for all SecretEntryPayload and save
+ // 24 bytes of storage and bandwidth for each of them.
+ //
+ // See https://pynacl.readthedocs.io/en/stable/secret/#nonce
+ // See Security Model here: https://nacl.cr.yp.to/box.html
+ var nonce [cryptoutil.NonceSize]byte
+
+ gid := group.GetPublicKey()
+
+ copy(nonce[:], gid)
+
+ return &nonce
+}
diff --git a/pkg/secretstore/datastore_keys.go b/pkg/secretstore/datastore_keys.go
new file mode 100644
index 00000000..24a805f8
--- /dev/null
+++ b/pkg/secretstore/datastore_keys.go
@@ -0,0 +1,117 @@
+package secretstore
+
+import (
+ "encoding/base64"
+ "encoding/hex"
+ "fmt"
+
+ "github.com/ipfs/go-cid"
+ "github.com/ipfs/go-datastore"
+ "github.com/libp2p/go-libp2p/core/crypto"
+
+ "berty.tech/weshnet/pkg/errcode"
+)
+
+const (
+ // dsNamespaceChainKeyForDeviceOnGroup is a namespace stores the current
+ // state of a device chain key for a given group.
+ // It contains the secret used to derive the next value of the chain key
+ // and used to generate a message key for the message at `counter` value,
+ // then put in the dsNamespacePrecomputedMessageKeys namespace.
+ dsNamespaceChainKeyForDeviceOnGroup = "chainKeyForDeviceOnGroup"
+
+ // dsNamespacePrecomputedMessageKeys is a namespace storing precomputed
+ // message keys for a given group, device and message counter.
+ // As the chain key stored has already been derived, these message keys
+ // need to be computed beforehand.
+ // The corresponding message can then be decrypted via a quick lookup.
+ dsNamespacePrecomputedMessageKeys = "precomputedMessageKeys"
+
+ // dsNamespaceMessageKeyForCIDs is a namespace containing the message key
+ // for a given CID once the corresponding message has been decrypted.
+ dsNamespaceMessageKeyForCIDs = "messageKeyForCIDs"
+
+ // dsNamespaceOutOfStoreGroupHint is a namespace where HMAC value are
+ // associated to a group public key.
+ // It is used when receiving an out-of-store message (e.g. a push
+ // notification) to identify the group on which the message belongs, which
+ // can then be decrypted.
+ dsNamespaceOutOfStoreGroupHint = "outOfStoreGroupHint"
+
+ // dsNamespaceOutOfStoreGroupHintCounters is a namespace storing first and
+ // last counter values for generated group hints inside the
+ // dsNamespaceOutOfStoreGroupHint namespace
+ dsNamespaceOutOfStoreGroupHintCounters = "outOfStoreGroupHintCounters"
+
+ // dsNamespaceGroupDatastore is a namespace to store groups by their public
+ // key
+ dsNamespaceGroupDatastore = "groupByPublicKey"
+)
+
+func dsKeyForGroup(key []byte) datastore.Key {
+ return datastore.KeyWithNamespaces([]string{
+ dsNamespaceGroupDatastore,
+ base64.RawURLEncoding.EncodeToString(key),
+ })
+}
+
+// dsKeyForPrecomputedMessageKey returns a datastore.Key where will be stored a
+// precalculated message key for a given group and device
+func dsKeyForPrecomputedMessageKey(groupPublicKey, devicePublicKey []byte, counter uint64) datastore.Key {
+ return datastore.KeyWithNamespaces([]string{
+ dsNamespacePrecomputedMessageKeys,
+ hex.EncodeToString(groupPublicKey),
+ hex.EncodeToString(devicePublicKey),
+ fmt.Sprintf("%d", counter),
+ })
+}
+
+// dsKeyForCurrentChainKey returns a datastore.Key where will be stored a
+// device chain key for a given group.
+func dsKeyForCurrentChainKey(groupPublicKey crypto.PubKey, devicePublicKey crypto.PubKey) (datastore.Key, error) {
+ devicePublicKeyBytes, err := devicePublicKey.Raw()
+ if err != nil {
+ return datastore.Key{}, errcode.ErrSerialization.Wrap(err)
+ }
+
+ groupPublicKeyBytes, err := groupPublicKey.Raw()
+ if err != nil {
+ return datastore.Key{}, errcode.ErrSerialization.Wrap(err)
+ }
+
+ return datastore.KeyWithNamespaces([]string{
+ dsNamespaceChainKeyForDeviceOnGroup,
+ hex.EncodeToString(groupPublicKeyBytes),
+ hex.EncodeToString(devicePublicKeyBytes),
+ }), nil
+}
+
+// dsKeyForMessageKeyByCID returns a datastore.Key where will be stored a
+// message decryption key for a given message CID.
+func dsKeyForMessageKeyByCID(id cid.Cid) datastore.Key {
+ // TODO: specify the id
+ return datastore.KeyWithNamespaces([]string{
+ dsNamespaceMessageKeyForCIDs,
+ id.String(),
+ })
+}
+
+// dsKeyForOutOfStoreMessageGroupHint returns a datastore.Key where will be
+// stored a group public key for a given push group reference.
+func dsKeyForOutOfStoreMessageGroupHint(ref []byte) datastore.Key {
+ return datastore.KeyWithNamespaces([]string{
+ dsNamespaceOutOfStoreGroupHint,
+ base64.RawURLEncoding.EncodeToString(ref),
+ })
+}
+
+// dsKeyForOutOfStoreFirstLastCounters returns the datastore.Key where will be
+// stored a protocoltypes.FirstLastCounters struct for the given group public
+// key and device public key.
+func dsKeyForOutOfStoreFirstLastCounters(groupPK, devicePK []byte) datastore.Key {
+ return datastore.KeyWithNamespaces([]string{
+ dsNamespaceOutOfStoreGroupHintCounters,
+ base64.RawURLEncoding.EncodeToString(groupPK),
+ base64.RawURLEncoding.EncodeToString(devicePK),
+ })
+}
diff --git a/pkg/secretstore/device_keystore_wrapper.go b/pkg/secretstore/device_keystore_wrapper.go
new file mode 100644
index 00000000..79477ec3
--- /dev/null
+++ b/pkg/secretstore/device_keystore_wrapper.go
@@ -0,0 +1,259 @@
+package secretstore
+
+import (
+ "crypto/ed25519"
+ crand "crypto/rand"
+ "encoding/hex"
+ "fmt"
+ "strings"
+ "sync"
+
+ "github.com/aead/ecdh"
+ keystore "github.com/ipfs/go-ipfs-keystore"
+ "github.com/libp2p/go-libp2p/core/crypto"
+ "go.uber.org/zap"
+
+ "berty.tech/weshnet/pkg/cryptoutil"
+ "berty.tech/weshnet/pkg/errcode"
+ "berty.tech/weshnet/pkg/protocoltypes"
+)
+
+const (
+ keyAccount = "accountSK"
+ keyAccountProof = "accountProofSK"
+ keyDevice = "deviceSK"
+ keyMemberDevice = "memberDeviceSK"
+ keyMember = "memberSK"
+ keyContactGroup = "contactGroupSK"
+)
+
+// deviceKeystore is a wrapper around a keystore.Keystore object.
+// It contains methods to manipulate member and device keys.
+type deviceKeystore struct {
+ keystore keystore.Keystore
+ mu sync.Mutex
+ logger *zap.Logger
+}
+
+// newDeviceKeystore instantiate a new device keystore
+func newDeviceKeystore(ks keystore.Keystore, logger *zap.Logger) *deviceKeystore {
+ if logger == nil {
+ logger = zap.NewNop()
+ }
+
+ return &deviceKeystore{
+ keystore: ks,
+ logger: logger,
+ }
+}
+
+// getAccountPrivateKey returns the private key of the current account
+func (a *deviceKeystore) getAccountPrivateKey() (crypto.PrivKey, error) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+
+ return a.getOrGenerateNamedKey(keyAccount)
+}
+
+// getAccountProofPrivateKey returns the private proof key of
+// the current account
+func (a *deviceKeystore) getAccountProofPrivateKey() (crypto.PrivKey, error) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+
+ return a.getOrGenerateNamedKey(keyAccountProof)
+}
+
+// devicePrivateKey returns the current private key of the current device for
+// the account and one-to-one conversations
+func (a *deviceKeystore) devicePrivateKey() (crypto.PrivKey, error) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+
+ return a.getOrGenerateNamedKey(keyDevice)
+}
+
+// contactGroupPrivateKey retrieves the key for the contact group
+// shared with the supplied contact's public key, this key will be derived to
+// form the contact group keys
+func (a *deviceKeystore) contactGroupPrivateKey(contactPublicKey crypto.PubKey) (crypto.PrivKey, error) {
+ accountPrivateKey, err := a.getAccountPrivateKey()
+ if err != nil {
+ return nil, errcode.ErrInternal.Wrap(err)
+ }
+
+ return a.getOrComputeECDH(keyContactGroup, contactPublicKey, accountPrivateKey)
+}
+
+// memberDeviceForMultiMemberGroup retrieves the device private key for the
+// supplied group
+func (a *deviceKeystore) memberDeviceForMultiMemberGroup(groupPublicKey crypto.PubKey) (*ownMemberDevice, error) {
+ memberPrivateKey, err := a.computeMemberKeyForMultiMemberGroup(groupPublicKey)
+ if err != nil {
+ return nil, errcode.ErrInternal.Wrap(fmt.Errorf("unable to get or generate a device key for group member: %w", err))
+ }
+
+ devicePrivateKey, err := a.getOrGenerateDeviceKeyForMultiMemberGroup(groupPublicKey)
+ if err != nil {
+ return nil, errcode.ErrInternal.Wrap(err)
+ }
+
+ return newOwnMemberDevice(memberPrivateKey, devicePrivateKey), nil
+}
+
+// memberDeviceForGroup computes or retrieves the member and device key for the
+// supplied group
+func (a *deviceKeystore) memberDeviceForGroup(group *protocoltypes.Group) (*ownMemberDevice, error) {
+ publicKey, err := group.GetPubKey()
+ if err != nil {
+ return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("unable to get public key for group: %w", err))
+ }
+
+ switch group.GetGroupType() {
+ case protocoltypes.GroupTypeAccount, protocoltypes.GroupTypeContact:
+ memberPrivateKey, err := a.getAccountPrivateKey()
+ if err != nil {
+ return nil, errcode.ErrInternal.Wrap(err)
+ }
+
+ devicePrivateKey, err := a.devicePrivateKey()
+ if err != nil {
+ return nil, errcode.ErrInternal.Wrap(err)
+ }
+
+ return newOwnMemberDevice(memberPrivateKey, devicePrivateKey), nil
+
+ case protocoltypes.GroupTypeMultiMember:
+ return a.memberDeviceForMultiMemberGroup(publicKey)
+ }
+
+ return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("unknown group type"))
+}
+
+// getOrGenerateNamedKey retrieves a private key by its name, or generate it
+// if missing
+func (a *deviceKeystore) getOrGenerateNamedKey(name string) (crypto.PrivKey, error) {
+ privateKey, err := a.keystore.Get(name)
+ if err == nil {
+ return privateKey, nil
+ } else if err.Error() != keystore.ErrNoSuchKey.Error() {
+ return nil, errcode.ErrDBRead.Wrap(fmt.Errorf("unable to perform get operation on keystore: %w", err))
+ }
+
+ privateKey, _, err = crypto.GenerateEd25519Key(crand.Reader)
+ if err != nil {
+ return nil, errcode.ErrCryptoKeyGeneration.Wrap(fmt.Errorf("unable to generate an ed25519 key: %w", err))
+ }
+
+ if err := a.keystore.Put(name, privateKey); err != nil {
+ return nil, errcode.ErrDBWrite.Wrap(fmt.Errorf("unable to perform put operation on keystore: %w", err))
+ }
+
+ return privateKey, nil
+}
+
+// getOrGenerateDeviceKeyForMultiMemberGroup fetches or generate a new device
+// key for a multi-member group. The results do not need to be deterministic
+// as it will only be used on the current device.
+func (a *deviceKeystore) getOrGenerateDeviceKeyForMultiMemberGroup(groupPublicKey crypto.PubKey) (crypto.PrivKey, error) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+
+ groupPublicKeyRaw, err := groupPublicKey.Raw()
+ if err != nil {
+ return nil, errcode.ErrSerialization.Wrap(err)
+ }
+
+ name := strings.Join([]string{keyMemberDevice, hex.EncodeToString(groupPublicKeyRaw)}, "_")
+
+ return a.getOrGenerateNamedKey(name)
+}
+
+// getOrComputeECDH fetches a named private key or computes one via an
+// elliptic-curve Diffie-Hellman key agreement if not cached
+func (a *deviceKeystore) getOrComputeECDH(nameSpace string, publicKey crypto.PubKey, ownPrivateKey crypto.PrivKey) (crypto.PrivKey, error) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+
+ publicKeyRaw, err := publicKey.Raw()
+ if err != nil {
+ return nil, errcode.ErrSerialization.Wrap(err)
+ }
+
+ name := strings.Join([]string{nameSpace, hex.EncodeToString(publicKeyRaw)}, "_")
+
+ privateKey, err := a.keystore.Get(name)
+ if err == nil {
+ return privateKey, nil
+ } else if err.Error() != keystore.ErrNoSuchKey.Error() {
+ return nil, errcode.ErrDBRead.Wrap(fmt.Errorf("unable to perform get operation on keystore: %w", err))
+ }
+
+ privateKeyBytes, publicKeyBytes, err := cryptoutil.EdwardsToMontgomery(ownPrivateKey, publicKey)
+ if err != nil {
+ return nil, errcode.ErrCryptoKeyConversion.Wrap(err)
+ }
+
+ secret := ecdh.X25519().ComputeSecret(privateKeyBytes, publicKeyBytes)
+ groupSecretPrivateKey := ed25519.NewKeyFromSeed(secret)
+
+ privateKey, _, err = crypto.KeyPairFromStdKey(&groupSecretPrivateKey)
+ if err != nil {
+ return nil, errcode.ErrCryptoKeyConversion.Wrap(err)
+ }
+
+ if err := a.keystore.Put(name, privateKey); err != nil {
+ return nil, errcode.ErrDBWrite.Wrap(err)
+ }
+
+ return privateKey, nil
+}
+
+// computeMemberKeyForMultiMemberGroup returns a deterministic private key
+// for a multi member group, this allows a group to be joined from two
+// different devices simultaneously without requiring a consensus.
+func (a *deviceKeystore) computeMemberKeyForMultiMemberGroup(groupPublicKey crypto.PubKey) (crypto.PrivKey, error) {
+ accountProofPrivateKey, err := a.getAccountProofPrivateKey()
+ if err != nil {
+ return nil, errcode.ErrInternal.Wrap(err)
+ }
+
+ return a.getOrComputeECDH(keyMember, groupPublicKey, accountProofPrivateKey)
+}
+
+// restoreAccountKeys restores exported LibP2P keys into the deviceKeystore, it
+// will fail if accounts keys are already created or imported into the keystore
+func (a *deviceKeystore) restoreAccountKeys(accountPrivateKeyBytes []byte, accountProofPrivateKeyBytes []byte) error {
+ privateKeys := map[string]crypto.PrivKey{}
+
+ for keyName, keyBytes := range map[string][]byte{
+ keyAccount: accountPrivateKeyBytes,
+ keyAccountProof: accountProofPrivateKeyBytes,
+ } {
+ var err error
+ privateKeys[keyName], err = getEd25519PrivateKeyFromLibP2PFormattedBytes(keyBytes)
+ if err != nil {
+ return errcode.ErrDeserialization.Wrap(err)
+ }
+ }
+
+ if privateKeys[keyAccount].Equals(privateKeys[keyAccountProof]) {
+ return errcode.ErrInvalidInput.Wrap(fmt.Errorf("the account key cannot be the same value as the account proof key"))
+ }
+
+ for keyName := range privateKeys {
+ if exists, err := a.keystore.Has(keyName); err != nil {
+ return errcode.ErrDBRead.Wrap(err)
+ } else if exists {
+ return errcode.ErrInvalidInput.Wrap(fmt.Errorf("an account is already set in this keystore"))
+ }
+ }
+
+ for keyName, privateKey := range privateKeys {
+ if err := a.keystore.Put(keyName, privateKey); err != nil {
+ return errcode.ErrDBWrite.Wrap(err)
+ }
+ }
+
+ return nil
+}
diff --git a/pkg/secretstore/device_keystore_wrapper_test.go b/pkg/secretstore/device_keystore_wrapper_test.go
new file mode 100644
index 00000000..023f99fa
--- /dev/null
+++ b/pkg/secretstore/device_keystore_wrapper_test.go
@@ -0,0 +1,207 @@
+package secretstore_test
+
+import (
+ crand "crypto/rand"
+ "testing"
+
+ "github.com/libp2p/go-libp2p/core/crypto"
+ "github.com/stretchr/testify/assert"
+
+ "berty.tech/weshnet/pkg/protocoltypes"
+ "berty.tech/weshnet/pkg/secretstore"
+)
+
+func Test_New_AccountPrivKey_AccountProofPrivKey(t *testing.T) {
+ acc, err := secretstore.NewInMemSecretStore(nil)
+ assert.NoError(t, err)
+ assert.NotNil(t, acc)
+
+ sk1, skProof1, err := acc.ExportAccountKeysForBackup()
+ assert.NoError(t, err)
+ assert.NotNil(t, sk1)
+ assert.NotNil(t, skProof1)
+
+ sk2, skProof2, err := acc.ExportAccountKeysForBackup()
+ assert.NoError(t, err)
+ assert.NotNil(t, sk2)
+ assert.NotNil(t, skProof2)
+
+ assert.Equal(t, sk1, sk2)
+ assert.Equal(t, skProof1, skProof2)
+
+ assert.NotEqual(t, sk1, skProof1)
+ assert.NotEqual(t, sk1, skProof2)
+ assert.NotEqual(t, sk2, skProof1)
+ assert.NotEqual(t, sk2, skProof2)
+}
+
+func Test_ExportAccountKeys_ImportAccountKeys(t *testing.T) {
+ acc1, err := secretstore.NewInMemSecretStore(nil)
+ assert.NoError(t, err)
+ assert.NotNil(t, acc1)
+
+ sk1, skProof1, err := acc1.ExportAccountKeysForBackup()
+ assert.NoError(t, err)
+ assert.NotNil(t, sk1)
+ assert.NotNil(t, skProof1)
+
+ acc2, err := secretstore.NewInMemSecretStore(nil)
+ assert.NoError(t, err)
+ assert.NotNil(t, acc2)
+
+ // Testing with a nil value
+ {
+ assert.Error(t, acc2.ImportAccountKeys(nil, skProof1))
+ assert.Error(t, acc2.ImportAccountKeys(sk1, nil))
+ }
+
+ // Testing with an unsupported key format
+ {
+ invalidPriv, _, err := crypto.GenerateSecp256k1Key(crand.Reader)
+ assert.NoError(t, err)
+
+ invalidPrivBytes, err := crypto.MarshalPrivateKey(invalidPriv)
+ assert.NoError(t, err)
+
+ assert.Error(t, acc2.ImportAccountKeys(sk1, invalidPrivBytes))
+ assert.Error(t, acc2.ImportAccountKeys(invalidPrivBytes, skProof1))
+ }
+
+ // Testing with an invalid key format
+ {
+ garbageBytes := []byte("garbage")
+ assert.Error(t, acc2.ImportAccountKeys(sk1, garbageBytes))
+ assert.Error(t, acc2.ImportAccountKeys(garbageBytes, skProof1))
+ }
+
+ // Testing with account and proof key being the same
+ {
+ assert.Error(t, acc2.ImportAccountKeys(sk1, sk1))
+ }
+
+ // Valid test case
+ {
+ assert.NoError(t, acc2.ImportAccountKeys(sk1, skProof1))
+ }
+
+ // Attempting to import keys again
+ {
+ assert.Error(t, acc2.ImportAccountKeys(sk1, skProof1))
+ }
+
+ sk2, skProof2, err := acc1.ExportAccountKeysForBackup()
+ assert.NoError(t, err)
+ assert.NotNil(t, sk2)
+ assert.NotNil(t, skProof2)
+
+ assert.Equal(t, sk1, sk2)
+ assert.Equal(t, skProof1, skProof2)
+ assert.NotEqual(t, sk1, skProof1)
+ assert.NotEqual(t, sk1, skProof2)
+ assert.NotEqual(t, sk2, skProof1)
+ assert.NotEqual(t, sk2, skProof2)
+}
+
+func Test_DevicePrivKey(t *testing.T) {
+ acc1, err := secretstore.NewInMemSecretStore(nil)
+ assert.NoError(t, err)
+ assert.NotNil(t, acc1)
+
+ sk1, skProof1, err := acc1.ExportAccountKeysForBackup()
+ assert.NoError(t, err)
+ assert.NotNil(t, sk1)
+ assert.NotNil(t, skProof1)
+
+ acc2, err := secretstore.NewInMemSecretStore(nil)
+ assert.NoError(t, err)
+ assert.NotNil(t, acc1)
+
+ err = acc2.ImportAccountKeys(sk1, skProof1)
+ assert.NoError(t, err)
+
+ sk2, skProof2, err := acc2.ExportAccountKeysForBackup()
+ assert.NoError(t, err)
+ assert.NotNil(t, sk2)
+ assert.NotNil(t, skProof2)
+
+ accGroup1, memberDevice1, err := acc1.GetGroupForAccount()
+ assert.NoError(t, err)
+ assert.NotNil(t, accGroup1)
+
+ memberDevice2, err := acc2.GetOwnMemberDeviceForGroup(accGroup1)
+ assert.NoError(t, err)
+ assert.NotNil(t, memberDevice2)
+
+ assert.True(t, memberDevice1.Member().Equals(memberDevice2.Member()))
+ assert.False(t, memberDevice1.Device().Equals(memberDevice2.Device()))
+}
+
+func Test_ContactGroupPrivKey(t *testing.T) {
+ acc1, err := secretstore.NewInMemSecretStore(nil)
+ assert.NoError(t, err)
+ assert.NotNil(t, acc1)
+
+ _, acc1MemberDevice, err := acc1.GetGroupForAccount()
+ assert.NoError(t, err)
+ assert.NotNil(t, acc1MemberDevice)
+
+ acc2, err := secretstore.NewInMemSecretStore(nil)
+ assert.NoError(t, err)
+ assert.NotNil(t, acc2)
+
+ _, acc2MemberDevice, err := acc2.GetGroupForAccount()
+ assert.NoError(t, err)
+ assert.NotNil(t, acc2MemberDevice)
+
+ grp1, err := acc1.GetGroupForContact(acc2MemberDevice.Member())
+ assert.NoError(t, err)
+ assert.NotNil(t, grp1)
+
+ grp2, err := acc2.GetGroupForContact(acc1MemberDevice.Member())
+ assert.NoError(t, err)
+ assert.NotNil(t, grp2)
+
+ assert.Equal(t, grp1.PublicKey, grp2.PublicKey)
+ assert.Equal(t, grp1.Secret, grp2.Secret)
+ assert.Equal(t, grp1.GroupType, grp2.GroupType)
+}
+
+func Test_MemberDeviceForGroup_multimember(t *testing.T) {
+ acc1, err := secretstore.NewInMemSecretStore(nil)
+ assert.NoError(t, err)
+ assert.NotNil(t, acc1)
+
+ sk1, skProof1, err := acc1.ExportAccountKeysForBackup()
+ assert.NoError(t, err)
+ assert.NotNil(t, sk1)
+ assert.NotNil(t, skProof1)
+
+ acc2, err := secretstore.NewInMemSecretStore(nil)
+ assert.NoError(t, err)
+ assert.NotNil(t, acc2)
+
+ err = acc2.ImportAccountKeys(sk1, skProof1)
+ assert.NoError(t, err)
+
+ sk2, skProof2, err := acc2.ExportAccountKeysForBackup()
+ assert.NoError(t, err)
+ assert.NotNil(t, sk2)
+ assert.NotNil(t, skProof2)
+
+ g, _, err := protocoltypes.NewGroupMultiMember()
+ assert.NoError(t, err)
+
+ omd1, err := acc1.GetOwnMemberDeviceForGroup(g)
+ assert.NoError(t, err)
+
+ omd2, err := acc2.GetOwnMemberDeviceForGroup(g)
+ assert.NoError(t, err)
+
+ omd1M := omd1.Member()
+ omd2M := omd2.Member()
+ omd1D := omd1.Device()
+ omd2D := omd2.Device()
+
+ assert.True(t, omd1M.Equals(omd2M))
+ assert.False(t, omd1D.Equals(omd2D))
+}
diff --git a/pkg/secretstore/doc.go b/pkg/secretstore/doc.go
new file mode 100644
index 00000000..470aac9b
--- /dev/null
+++ b/pkg/secretstore/doc.go
@@ -0,0 +1,2 @@
+// Package secretstore contains function related to device, groups and messages keys.
+package secretstore
diff --git a/pkg/secretstore/keys_utils.go b/pkg/secretstore/keys_utils.go
new file mode 100644
index 00000000..9c5c0aaa
--- /dev/null
+++ b/pkg/secretstore/keys_utils.go
@@ -0,0 +1,147 @@
+package secretstore
+
+import (
+ "crypto/ed25519"
+ "crypto/sha256"
+ "encoding/binary"
+ "fmt"
+ "io"
+ "io/ioutil"
+
+ "github.com/libp2p/go-libp2p/core/crypto"
+ crypto_pb "github.com/libp2p/go-libp2p/core/crypto/pb"
+ "golang.org/x/crypto/hkdf"
+ "golang.org/x/crypto/sha3"
+
+ "berty.tech/weshnet/pkg/cryptoutil"
+ "berty.tech/weshnet/pkg/errcode"
+ "berty.tech/weshnet/pkg/protocoltypes"
+)
+
+// getEd25519PrivateKeyFromLibP2PFormattedBytes transforms an exported LibP2P
+// private key into a crypto.PrivKey instance, ensuring it is an ed25519 key
+func getEd25519PrivateKeyFromLibP2PFormattedBytes(rawKeyBytes []byte) (crypto.PrivKey, error) {
+ if len(rawKeyBytes) == 0 {
+ return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("missing key data"))
+ }
+
+ privateKey, err := crypto.UnmarshalPrivateKey(rawKeyBytes)
+ if err != nil {
+ return nil, errcode.ErrInvalidInput.Wrap(err)
+ }
+
+ if privateKey.Type() != crypto_pb.KeyType_Ed25519 {
+ return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("invalid key format"))
+ }
+
+ return privateKey, nil
+}
+
+// getKeysForGroupOfContact returns derived private keys for contact group
+// using a private key via two accounts account keys (via an ECDH).
+func getKeysForGroupOfContact(contactPairPrivateKey crypto.PrivKey) (crypto.PrivKey, crypto.PrivKey, error) {
+ // Salt length must be equal to hash length (64 bytes for sha256)
+ hash := sha256.New
+
+ contactPairPrivateKeyBytes, err := contactPairPrivateKey.Raw()
+ if err != nil {
+ return nil, nil, errcode.ErrSerialization.Wrap(err)
+ }
+
+ // Generate Pseudo Random Key using contactPairPrivateKeyBytes as IKM and salt
+ prk := hkdf.Extract(hash, contactPairPrivateKeyBytes, nil)
+ if len(prk) == 0 {
+ return nil, nil, errcode.ErrInternal.Wrap(fmt.Errorf("unable to instantiate pseudo random key"))
+ }
+
+ // Expand using extracted prk and groupID as info (kind of namespace)
+ kdf := hkdf.Expand(hash, prk, nil)
+
+ // Generate next KDF and message keys
+ groupSeed, err := ioutil.ReadAll(io.LimitReader(kdf, 32))
+ if err != nil {
+ return nil, nil, errcode.ErrCryptoKeyGeneration.Wrap(err)
+ }
+
+ groupSecretSeed, err := ioutil.ReadAll(io.LimitReader(kdf, 32))
+ if err != nil {
+ return nil, nil, errcode.ErrCryptoKeyGeneration.Wrap(err)
+ }
+
+ stdGroupPrivateKey := ed25519.NewKeyFromSeed(groupSeed)
+ groupPrivateKey, _, err := crypto.KeyPairFromStdKey(&stdGroupPrivateKey)
+ if err != nil {
+ return nil, nil, errcode.ErrCryptoKeyGeneration.Wrap(err)
+ }
+
+ stdGroupSecretPrivateKey := ed25519.NewKeyFromSeed(groupSecretSeed)
+ groupSecretPrivateKey, _, err := crypto.KeyPairFromStdKey(&stdGroupSecretPrivateKey)
+ if err != nil {
+ return nil, nil, errcode.ErrCryptoKeyGeneration.Wrap(err)
+ }
+
+ return groupPrivateKey, groupSecretPrivateKey, nil
+}
+
+// getGroupForContact returns a protocoltypes.Group instance for a contact,
+// using a private key via two accounts account keys (via an ECDH)
+func getGroupForContact(contactPairPrivateKey crypto.PrivKey) (*protocoltypes.Group, error) {
+ groupPrivateKey, groupSecretPrivateKey, err := getKeysForGroupOfContact(contactPairPrivateKey)
+ if err != nil {
+ return nil, errcode.ErrCryptoKeyGeneration.Wrap(err)
+ }
+
+ pubBytes, err := groupPrivateKey.GetPublic().Raw()
+ if err != nil {
+ return nil, errcode.ErrSerialization.Wrap(err)
+ }
+
+ signingBytes, err := cryptoutil.SeedFromEd25519PrivateKey(groupSecretPrivateKey)
+ if err != nil {
+ return nil, errcode.ErrSerialization.Wrap(err)
+ }
+
+ return &protocoltypes.Group{
+ PublicKey: pubBytes,
+ Secret: signingBytes,
+ SecretSig: nil,
+ GroupType: protocoltypes.GroupTypeContact,
+ }, nil
+}
+
+// getGroupOutOfStoreSecret retrieves the out of store group secret
+func getGroupOutOfStoreSecret(m *protocoltypes.Group) ([]byte, error) {
+ if len(m.GetSecret()) == 0 {
+ return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("no secret known for group"))
+ }
+
+ arr := [cryptoutil.KeySize]byte{}
+
+ kdf := hkdf.New(sha3.New256, m.GetSecret(), nil, []byte(namespaceOutOfStoreSecret))
+ if _, err := io.ReadFull(kdf, arr[:]); err != nil {
+ return nil, errcode.ErrStreamRead.Wrap(err)
+ }
+
+ return arr[:], nil
+}
+
+// createOutOfStoreGroupReference creates a hash used to identify an out of
+// store (e.g. push notification) message origin
+func createOutOfStoreGroupReference(m *protocoltypes.Group, sender []byte, counter uint64) ([]byte, error) {
+ secret, err := getGroupOutOfStoreSecret(m)
+ if err != nil {
+ return nil, errcode.ErrInvalidInput.Wrap(err)
+ }
+
+ arr := [cryptoutil.KeySize]byte{}
+
+ buf := make([]byte, 8)
+ binary.BigEndian.PutUint64(buf, counter)
+
+ kdf := hkdf.New(sha3.New256, secret, nil, append(sender, buf...))
+ if _, err := io.ReadFull(kdf, arr[:]); err != nil {
+ return nil, errcode.ErrStreamRead.Wrap(err)
+ }
+
+ return arr[:], nil
+}
diff --git a/pkg/secretstore/member_device.go b/pkg/secretstore/member_device.go
new file mode 100644
index 00000000..daed5b9c
--- /dev/null
+++ b/pkg/secretstore/member_device.go
@@ -0,0 +1,62 @@
+package secretstore
+
+import (
+ "github.com/libp2p/go-libp2p/core/crypto"
+)
+
+type ownMemberDevice struct {
+ member crypto.PrivKey
+ device crypto.PrivKey
+ public *memberDevice
+}
+
+// newOwnMemberDevice instantiate a new ownMemberDevice allowing signing
+// and encrypting data as both a device or a member part of a group.
+// It also contains the public counterpart of the member and device keys.
+func newOwnMemberDevice(member, device crypto.PrivKey) *ownMemberDevice {
+ return &ownMemberDevice{
+ member: member,
+ device: device,
+ public: newMemberDevice(member.GetPublic(), device.GetPublic()),
+ }
+}
+
+func (d *ownMemberDevice) MemberSign(data []byte) ([]byte, error) {
+ return d.member.Sign(data)
+}
+
+func (d *ownMemberDevice) DeviceSign(data []byte) ([]byte, error) {
+ return d.device.Sign(data)
+}
+
+func (d *ownMemberDevice) Member() crypto.PubKey {
+ return d.public.member
+}
+
+func (d *ownMemberDevice) Device() crypto.PubKey {
+ return d.public.device
+}
+
+type memberDevice struct {
+ member crypto.PubKey
+ device crypto.PubKey
+}
+
+func NewMemberDevice(member, device crypto.PubKey) MemberDevice {
+ return newMemberDevice(member, device)
+}
+
+func newMemberDevice(member, device crypto.PubKey) *memberDevice {
+ return &memberDevice{
+ member: member,
+ device: device,
+ }
+}
+
+func (m *memberDevice) Member() crypto.PubKey {
+ return m.member
+}
+
+func (m *memberDevice) Device() crypto.PubKey {
+ return m.device
+}
diff --git a/pkg/secretstore/secret_store.go b/pkg/secretstore/secret_store.go
new file mode 100644
index 00000000..3ae12961
--- /dev/null
+++ b/pkg/secretstore/secret_store.go
@@ -0,0 +1,379 @@
+package secretstore
+
+import (
+ "context"
+ "fmt"
+ "sync"
+
+ "github.com/ipfs/go-cid"
+ "github.com/ipfs/go-datastore"
+ dssync "github.com/ipfs/go-datastore/sync"
+ "github.com/libp2p/go-libp2p/core/crypto"
+ "go.uber.org/zap"
+ "golang.org/x/crypto/nacl/secretbox"
+
+ "berty.tech/weshnet/internal/datastoreutil"
+ "berty.tech/weshnet/pkg/cryptoutil"
+ "berty.tech/weshnet/pkg/errcode"
+ "berty.tech/weshnet/pkg/ipfsutil"
+ "berty.tech/weshnet/pkg/protocoltypes"
+ "berty.tech/weshnet/pkg/pushtypes"
+)
+
+const (
+ namespaceDeviceKeystore = "device_keystore"
+ namespaceOutOfStoreSecret = "push_secret_ref" // nolint:gosec
+)
+
+type secretStore struct {
+ logger *zap.Logger
+ datastore datastore.Datastore
+ deviceKeystore *deviceKeystore
+
+ messageMutex sync.RWMutex
+
+ preComputedKeysCount int
+ precomputeOutOfStoreGroupRefsCount uint64
+}
+
+func (o *NewSecretStoreOptions) applyDefaults(rootDatastore datastore.Datastore) {
+ if o.Logger == nil {
+ o.Logger = zap.NewNop()
+ }
+
+ if o.Keystore == nil {
+ o.Keystore = ipfsutil.NewDatastoreKeystore(datastoreutil.NewNamespacedDatastore(rootDatastore, datastore.NewKey(namespaceDeviceKeystore)))
+ }
+
+ if o.PreComputedKeysCount <= 0 {
+ o.PreComputedKeysCount = PrecomputeMessageKeyCount
+ }
+
+ if o.PrecomputeOutOfStoreGroupRefsCount <= 0 {
+ o.PrecomputeOutOfStoreGroupRefsCount = PrecomputeOutOfStoreGroupRefsCount
+ }
+}
+
+// NewSecretStore instantiates a new SecretStore
+func NewSecretStore(rootDatastore datastore.Datastore, opts *NewSecretStoreOptions) (SecretStore, error) {
+ return newSecretStore(rootDatastore, opts)
+}
+
+// newSecretStore instantiates a new secretStore
+func newSecretStore(rootDatastore datastore.Datastore, opts *NewSecretStoreOptions) (*secretStore, error) {
+ if rootDatastore == nil {
+ return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("a datastore is required"))
+ }
+
+ if opts == nil {
+ opts = &NewSecretStoreOptions{}
+ }
+
+ opts.applyDefaults(rootDatastore)
+
+ devKeystore := newDeviceKeystore(opts.Keystore, opts.Logger)
+
+ store := &secretStore{
+ logger: opts.Logger,
+ datastore: rootDatastore,
+ deviceKeystore: devKeystore,
+
+ preComputedKeysCount: opts.PreComputedKeysCount,
+ precomputeOutOfStoreGroupRefsCount: uint64(opts.PrecomputeOutOfStoreGroupRefsCount),
+ }
+
+ return store, nil
+}
+
+// NewInMemSecretStore instantiates a SecretStore using a volatile backend.
+func NewInMemSecretStore(opts *NewSecretStoreOptions) (SecretStore, error) {
+ return newInMemSecretStore(opts)
+}
+
+// newInMemSecretStore instantiates a secretStore using a volatile backend.
+func newInMemSecretStore(opts *NewSecretStoreOptions) (*secretStore, error) {
+ return newSecretStore(dssync.MutexWrap(datastore.NewMapDatastore()), opts)
+}
+
+func (s *secretStore) Close() error {
+ return nil
+}
+
+func (s *secretStore) PutGroup(ctx context.Context, g *protocoltypes.Group) error {
+ pk, err := g.GetPubKey()
+ if err != nil {
+ return errcode.ErrInvalidInput.Wrap(err)
+ }
+
+ // TODO: check if partial group or full group and complete if necessary
+ if ok, err := s.hasGroup(ctx, pk); err != nil {
+ return errcode.ErrInvalidInput.Wrap(err)
+ } else if ok {
+ return nil
+ }
+
+ data, err := g.Marshal()
+ if err != nil {
+ return errcode.ErrSerialization.Wrap(err)
+ }
+
+ if err := s.datastore.Put(ctx, dsKeyForGroup(g.GetPublicKey()), data); err != nil {
+ return errcode.ErrKeystorePut.Wrap(err)
+ }
+
+ memberDevice, err := s.GetOwnMemberDeviceForGroup(g)
+ if err != nil {
+ return errcode.ErrInternal.Wrap(err)
+ }
+
+ // Force generation of chain key for own device
+ _, err = s.GetShareableChainKey(ctx, g, memberDevice.Member())
+ if err != nil {
+ return errcode.ErrInternal.Wrap(err)
+ }
+
+ return nil
+}
+
+func (s *secretStore) GetOwnMemberDeviceForGroup(g *protocoltypes.Group) (OwnMemberDevice, error) {
+ return s.deviceKeystore.memberDeviceForGroup(g)
+}
+
+func (s *secretStore) OpenOutOfStoreMessage(ctx context.Context, payload []byte) (*protocoltypes.OutOfStoreMessage, *protocoltypes.Group, []byte, bool, error) {
+ oosMessageEnv := &pushtypes.OutOfStoreMessageEnvelope{}
+ if err := oosMessageEnv.Unmarshal(payload); err != nil {
+ return nil, nil, nil, false, errcode.ErrDeserialization.Wrap(err)
+ }
+
+ groupPublicKey, err := s.OutOfStoreGetGroupPublicKeyByGroupReference(ctx, oosMessageEnv.GroupReference)
+ if err != nil {
+ return nil, nil, nil, false, errcode.ErrNotFound.Wrap(err)
+ }
+
+ oosMessage, err := s.decryptOutOfStoreMessageEnv(ctx, oosMessageEnv, groupPublicKey)
+ if err != nil {
+ return nil, nil, nil, false, errcode.ErrCryptoDecrypt.Wrap(err)
+ }
+
+ clear, newlyDecrypted, err := s.OutOfStoreMessageOpen(ctx, oosMessage, groupPublicKey)
+ if err != nil {
+ return nil, nil, nil, false, errcode.ErrCryptoDecrypt.Wrap(err)
+ }
+
+ group, err := s.FetchGroupByPublicKey(ctx, groupPublicKey)
+ if err == nil {
+ if err := s.UpdateOutOfStoreGroupReferences(ctx, oosMessage.DevicePK, oosMessage.Counter, group); err != nil {
+ s.logger.Error("unable to update push group references", zap.Error(err))
+ }
+ }
+
+ return oosMessage, group, clear, !newlyDecrypted, nil
+}
+
+func (s *secretStore) decryptOutOfStoreMessageEnv(ctx context.Context, env *pushtypes.OutOfStoreMessageEnvelope, groupPK crypto.PubKey) (*protocoltypes.OutOfStoreMessage, error) {
+ nonce, err := cryptoutil.NonceSliceToArray(env.Nonce)
+ if err != nil {
+ return nil, errcode.ErrInvalidInput.Wrap(err)
+ }
+
+ g, err := s.FetchGroupByPublicKey(ctx, groupPK)
+ if err != nil {
+ return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("unable to find group, err: %w", err))
+ }
+
+ secret := g.GetSharedSecret()
+
+ data, ok := secretbox.Open(nil, env.Box, nonce, secret)
+ if !ok {
+ return nil, errcode.ErrCryptoDecrypt.Wrap(fmt.Errorf("unable to decrypt message"))
+ }
+
+ outOfStoreMessage := &protocoltypes.OutOfStoreMessage{}
+ if err := outOfStoreMessage.Unmarshal(data); err != nil {
+ return nil, errcode.ErrDeserialization.Wrap(err)
+ }
+
+ return outOfStoreMessage, nil
+}
+
+func (s *secretStore) FetchGroupByPublicKey(ctx context.Context, publicKey crypto.PubKey) (*protocoltypes.Group, error) {
+ keyBytes, err := publicKey.Raw()
+ if err != nil {
+ return nil, errcode.ErrSerialization.Wrap(err)
+ }
+
+ data, err := s.datastore.Get(ctx, dsKeyForGroup(keyBytes))
+ if err != nil {
+ return nil, errcode.ErrMissingMapKey.Wrap(err)
+ }
+
+ g := &protocoltypes.Group{}
+ if err := g.Unmarshal(data); err != nil {
+ return nil, errcode.ErrDeserialization.Wrap(err)
+ }
+
+ return g, nil
+}
+
+func (s *secretStore) GetAccountProofPublicKey() (crypto.PubKey, error) {
+ privateKey, err := s.deviceKeystore.getAccountPrivateKey()
+ if err != nil {
+ return nil, errcode.ErrInternal.Wrap(err)
+ }
+
+ return privateKey.GetPublic(), nil
+}
+
+func (s *secretStore) ImportAccountKeys(accountPrivateKeyBytes []byte, accountProofPrivateKeyBytes []byte) error {
+ return s.deviceKeystore.restoreAccountKeys(accountPrivateKeyBytes, accountProofPrivateKeyBytes)
+}
+
+func (s *secretStore) ExportAccountKeysForBackup() (accountPrivateKeyBytes []byte, accountProofPrivateKeyBytes []byte, err error) {
+ accountPrivateKey, err := s.deviceKeystore.getAccountPrivateKey()
+ if err != nil {
+ return nil, nil, errcode.ErrInternal.Wrap(err)
+ }
+
+ accountProofPrivateKey, err := s.deviceKeystore.getAccountProofPrivateKey()
+ if err != nil {
+ return nil, nil, errcode.ErrInternal.Wrap(err)
+ }
+
+ accountPrivateKeyBytes, err = crypto.MarshalPrivateKey(accountPrivateKey)
+ if err != nil {
+ return nil, nil, errcode.ErrSerialization.Wrap(err)
+ }
+
+ accountProofPrivateKeyBytes, err = crypto.MarshalPrivateKey(accountProofPrivateKey)
+ if err != nil {
+ return nil, nil, errcode.ErrSerialization.Wrap(err)
+ }
+
+ return accountPrivateKeyBytes, accountProofPrivateKeyBytes, nil
+}
+
+func (s *secretStore) GetAccountPrivateKey() (crypto.PrivKey, error) {
+ accountPrivateKey, err := s.deviceKeystore.getAccountPrivateKey()
+ if err != nil {
+ return nil, errcode.ErrInternal.Wrap(err)
+ }
+
+ return accountPrivateKey, nil
+}
+
+func (s *secretStore) GetGroupForAccount() (*protocoltypes.Group, OwnMemberDevice, error) {
+ accountPrivateKey, err := s.deviceKeystore.getAccountPrivateKey()
+ if err != nil {
+ return nil, nil, errcode.ErrOrbitDBOpen.Wrap(err)
+ }
+
+ accountProofPrivateKey, err := s.deviceKeystore.getAccountProofPrivateKey()
+ if err != nil {
+ return nil, nil, errcode.ErrOrbitDBOpen.Wrap(err)
+ }
+
+ devicePrivateKey, err := s.deviceKeystore.devicePrivateKey()
+ if err != nil {
+ return nil, nil, errcode.ErrInternal.Wrap(err)
+ }
+
+ pubBytes, err := accountPrivateKey.GetPublic().Raw()
+ if err != nil {
+ return nil, nil, errcode.ErrSerialization.Wrap(err)
+ }
+
+ signingBytes, err := cryptoutil.SeedFromEd25519PrivateKey(accountProofPrivateKey)
+ if err != nil {
+ return nil, nil, errcode.ErrSerialization.Wrap(err)
+ }
+
+ return &protocoltypes.Group{
+ PublicKey: pubBytes,
+ Secret: signingBytes,
+ SecretSig: nil,
+ GroupType: protocoltypes.GroupTypeAccount,
+ }, newOwnMemberDevice(accountPrivateKey, devicePrivateKey), nil
+}
+
+func (s *secretStore) GetGroupForContact(contactPublicKey crypto.PubKey) (*protocoltypes.Group, error) {
+ contactPairPrivateKey, err := s.deviceKeystore.contactGroupPrivateKey(contactPublicKey)
+ if err != nil {
+ return nil, errcode.ErrCryptoKeyGeneration.Wrap(err)
+ }
+
+ return getGroupForContact(contactPairPrivateKey)
+}
+
+func (s *secretStore) OpenEnvelopeHeaders(data []byte, g *protocoltypes.Group) (*protocoltypes.MessageEnvelope, *protocoltypes.MessageHeaders, error) {
+ env := &protocoltypes.MessageEnvelope{}
+ err := env.Unmarshal(data)
+ if err != nil {
+ return nil, nil, errcode.ErrDeserialization.Wrap(err)
+ }
+
+ nonce, err := cryptoutil.NonceSliceToArray(env.Nonce)
+ if err != nil {
+ return nil, nil, errcode.ErrSerialization.Wrap(fmt.Errorf("unable to convert slice to array: %w", err))
+ }
+
+ headersBytes, ok := secretbox.Open(nil, env.MessageHeaders, nonce, g.GetSharedSecret())
+ if !ok {
+ return nil, nil, errcode.ErrCryptoDecrypt.Wrap(fmt.Errorf("secretbox failed to open headers"))
+ }
+
+ headers := &protocoltypes.MessageHeaders{}
+ if err := headers.Unmarshal(headersBytes); err != nil {
+ return nil, nil, errcode.ErrDeserialization.Wrap(err)
+ }
+
+ return env, headers, nil
+}
+
+func (s *secretStore) SealOutOfStoreMessageEnvelope(id cid.Cid, env *protocoltypes.MessageEnvelope, headers *protocoltypes.MessageHeaders, g *protocoltypes.Group) (*pushtypes.OutOfStoreMessageEnvelope, error) {
+ oosMessage := &protocoltypes.OutOfStoreMessage{
+ CID: id.Bytes(),
+ DevicePK: headers.DevicePK,
+ Counter: headers.Counter,
+ Sig: headers.Sig,
+ EncryptedPayload: env.Message,
+ Nonce: env.Nonce,
+ }
+
+ data, err := oosMessage.Marshal()
+ if err != nil {
+ return nil, errcode.ErrSerialization.Wrap(err)
+ }
+
+ nonce, err := cryptoutil.GenerateNonce()
+ if err != nil {
+ return nil, errcode.ErrCryptoNonceGeneration.Wrap(err)
+ }
+
+ secret, err := cryptoutil.KeySliceToArray(g.Secret)
+ if err != nil {
+ return nil, errcode.ErrCryptoKeyConversion.Wrap(fmt.Errorf("unable to convert slice to array: %w", err))
+ }
+
+ encryptedData := secretbox.Seal(nil, data, nonce, secret)
+
+ pushGroupRef, err := createOutOfStoreGroupReference(g, headers.DevicePK, headers.Counter)
+ if err != nil {
+ return nil, errcode.ErrCryptoKeyGeneration.Wrap(err)
+ }
+
+ return &pushtypes.OutOfStoreMessageEnvelope{
+ Nonce: nonce[:],
+ Box: encryptedData,
+ GroupReference: pushGroupRef,
+ }, nil
+}
+
+// hasGroup checks whether a group is already known by the secretStore
+func (s *secretStore) hasGroup(ctx context.Context, key crypto.PubKey) (bool, error) {
+ keyBytes, err := key.Raw()
+ if err != nil {
+ return false, errcode.ErrSerialization.Wrap(err)
+ }
+
+ return s.datastore.Has(ctx, dsKeyForGroup(keyBytes))
+}
diff --git a/pkg/secretstore/secret_store_interfaces.go b/pkg/secretstore/secret_store_interfaces.go
new file mode 100644
index 00000000..5291db7f
--- /dev/null
+++ b/pkg/secretstore/secret_store_interfaces.go
@@ -0,0 +1,152 @@
+package secretstore
+
+import (
+ "context"
+
+ "github.com/ipfs/go-cid"
+ keystore "github.com/ipfs/go-ipfs-keystore"
+ "github.com/libp2p/go-libp2p/core/crypto"
+ "go.uber.org/zap"
+
+ "berty.tech/weshnet/pkg/cryptoutil"
+ "berty.tech/weshnet/pkg/protocoltypes"
+ "berty.tech/weshnet/pkg/pushtypes"
+)
+
+const (
+ PrecomputeOutOfStoreGroupRefsCount = 100
+ PrecomputeMessageKeyCount = 100
+)
+
+type messageKey [32]byte
+
+type SecretStore interface {
+ //
+ // Account methods
+ //
+
+ // GetAccountProofPublicKey returns the user's account proof public key
+ GetAccountProofPublicKey() (accountProofPublicKey crypto.PubKey, err error)
+
+ // ImportAccountKeys restores backup of account keys into the SecretStore, it should fail if the store is already used by an account
+ ImportAccountKeys(accountPrivateKey []byte, accountProofPrivateKey []byte) error
+
+ // ExportAccountKeysForBackup returns the account's private key and proof private key of the user for a backup
+ ExportAccountKeysForBackup() (accountPrivateKey []byte, accountProofPrivateKey []byte, err error)
+
+ // GetAccountPrivateKey returns the account's private key, avoid using it, use GetGroupForAccount to get the account public key or sign data instead
+ GetAccountPrivateKey() (accountPrivateKey crypto.PrivKey, err error)
+
+ //
+ // Groups methods
+ //
+
+ // GetGroupForAccount returns the Account's Group of the user
+ GetGroupForAccount() (group *protocoltypes.Group, ownMemberDevice OwnMemberDevice, err error)
+
+ // GetGroupForContact returns a contact group for communicating with the provided account
+ GetGroupForContact(contactPublicKey crypto.PubKey) (group *protocoltypes.Group, err error)
+
+ // PutGroup stores a group into the store
+ PutGroup(ctx context.Context, group *protocoltypes.Group) error
+
+ // FetchGroupByPublicKey gets an account from the store using the provided public key
+ FetchGroupByPublicKey(ctx context.Context, publicKey crypto.PubKey) (group *protocoltypes.Group, err error)
+
+ //
+ // Envelopes methods
+ //
+
+ // OpenEnvelopeHeaders opens a message headers for a given group
+ OpenEnvelopeHeaders(data []byte, group *protocoltypes.Group) (*protocoltypes.MessageEnvelope, *protocoltypes.MessageHeaders, error)
+
+ // OpenEnvelopePayload opens a message payload with the given group headers
+ OpenEnvelopePayload(ctx context.Context, msgEnvelope *protocoltypes.MessageEnvelope, msgHeaders *protocoltypes.MessageHeaders, groupPublicKey crypto.PubKey, ownPublicKey crypto.PubKey, msgCID cid.Cid) (*protocoltypes.EncryptedMessage, error)
+
+ // SealEnvelope creates an encrypted payload to be sent to a group
+ SealEnvelope(ctx context.Context, group *protocoltypes.Group, messagePayload []byte) (sealedEnvelope []byte, err error)
+
+ //
+ // Group member-device pairs methods
+ //
+
+ // GetOwnMemberDeviceForGroup gets a member and device key-pairs representing the current device in a given group
+ GetOwnMemberDeviceForGroup(group *protocoltypes.Group) (OwnMemberDevice, error)
+
+ //
+ // Chain-keys methods
+ //
+
+ // RegisterChainKey records another device chain-key
+ RegisterChainKey(ctx context.Context, group *protocoltypes.Group, senderDevicePublicKey crypto.PubKey, encryptedDeviceChainKey []byte) error
+
+ // GetShareableChainKey returns a chain-key that can be decrypted by the provided member of a group
+ GetShareableChainKey(ctx context.Context, group *protocoltypes.Group, targetMemberPublicKey crypto.PubKey) (encryptedDeviceChainKey []byte, err error)
+
+ // IsChainKeyKnownForDevice checks whether a chain key of a device is already known
+ IsChainKeyKnownForDevice(ctx context.Context, groupPublicKey crypto.PubKey, devicePublicKey crypto.PubKey) (isKnown bool)
+
+ //
+ // Out-of-store messages methods
+ //
+
+ // SealOutOfStoreMessageEnvelope encrypts a message to be sent outside a synchronized store
+ SealOutOfStoreMessageEnvelope(id cid.Cid, env *protocoltypes.MessageEnvelope, headers *protocoltypes.MessageHeaders, group *protocoltypes.Group) (*pushtypes.OutOfStoreMessageEnvelope, error)
+
+ // OpenOutOfStoreMessage opens a message received outside a synchronized store
+ OpenOutOfStoreMessage(ctx context.Context, payload []byte) (outOfStoreMessage *protocoltypes.OutOfStoreMessage, group *protocoltypes.Group, clearPayload []byte, alreadyDecrypted bool, err error)
+
+ // UpdateOutOfStoreGroupReferences computes references of messages which might be received outside a synchronized store
+ UpdateOutOfStoreGroupReferences(ctx context.Context, devicePublicKeyBytes []byte, first uint64, group *protocoltypes.Group) error
+
+ // Close frees resources created by the secret store
+ Close() error
+}
+
+// NewSecretStoreOptions contains the options that can be passed to NewSecretStore
+type NewSecretStoreOptions struct {
+ // PreComputedKeysCount specifies the number of keys to precompute,
+ // defaults to PrecomputeMessageKeyCount
+ PreComputedKeysCount int
+
+ // PreComputedKeysCount specifies the number of out of store references
+ // to precompute, defaults to PrecomputeOutOfStoreGroupRefsCount
+ PrecomputeOutOfStoreGroupRefsCount int
+
+ // Keystore specifies an implementation of a keystore to be used, can be
+ // helpful if you want to rely on a hardware based keystore instead of a
+ // software one
+ Keystore keystore.Keystore
+
+ // Logger specifies which logger to use, logging is disabled by default
+ Logger *zap.Logger
+
+ // DisableOutOfStoreSupport explicitly disables support of out-of-store
+ // payloads
+ DisableOutOfStoreSupport bool
+
+ // OutOfStorePrivateKey sets the out-of-store key to decrypt payloads
+ // received via a server, alternatively you can use
+ // SecretStore.SetOutOfStoreDevicePrivateKey to set it
+ OutOfStorePrivateKey *[cryptoutil.KeySize]byte
+}
+
+// MemberDevice is the public keys of a device and its member
+type MemberDevice interface {
+ // Member returns the member public key
+ Member() crypto.PubKey
+
+ // Device returns the device public key
+ Device() crypto.PubKey
+}
+
+// OwnMemberDevice is a MemberDevice for the current device, able to sign data
+type OwnMemberDevice interface {
+ MemberDevice
+
+ // MemberSign signs the given data as a member of a group
+ MemberSign(data []byte) ([]byte, error)
+
+ // DeviceSign signs the given data as a device of a group
+ DeviceSign(data []byte) ([]byte, error)
+}
diff --git a/pkg/secretstore/secret_store_messages.go b/pkg/secretstore/secret_store_messages.go
new file mode 100644
index 00000000..d880be4a
--- /dev/null
+++ b/pkg/secretstore/secret_store_messages.go
@@ -0,0 +1,1067 @@
+package secretstore
+
+import (
+ "context"
+ "crypto/sha256"
+ "encoding/binary"
+ "fmt"
+ "io"
+ "io/ioutil"
+
+ "github.com/gogo/protobuf/proto"
+ "github.com/ipfs/go-cid"
+ "github.com/ipfs/go-datastore"
+ "github.com/libp2p/go-libp2p/core/crypto"
+ "go.uber.org/zap"
+ "golang.org/x/crypto/hkdf"
+ "golang.org/x/crypto/nacl/secretbox"
+
+ "berty.tech/weshnet/pkg/cryptoutil"
+ "berty.tech/weshnet/pkg/errcode"
+ "berty.tech/weshnet/pkg/logutil"
+ "berty.tech/weshnet/pkg/protocoltypes"
+)
+
+// decryptionContext contains context about a decrypted message, its CID, the
+// associated message key and whether it had been previously opened.
+type decryptionContext struct {
+ newlyDecrypted bool
+ messageKey *messageKey
+ cid cid.Cid
+}
+
+// computedMessageKey is a precomputed message key for a given counter used in the cache namespace.
+type computedMessageKey struct {
+ counter uint64
+ messageKey *messageKey
+}
+
+// getDeviceChainKeyForGroupAndDevice returns the device chain key for the given group and device.
+func (s *secretStore) getDeviceChainKeyForGroupAndDevice(ctx context.Context, groupPublicKey crypto.PubKey, devicePublicKey crypto.PubKey) (*protocoltypes.DeviceChainKey, error) {
+ if s == nil {
+ return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
+ }
+
+ key, err := dsKeyForCurrentChainKey(groupPublicKey, devicePublicKey)
+ if err != nil {
+ return nil, errcode.ErrInternal.Wrap(err)
+ }
+
+ // Not mutex here
+ dsBytes, err := s.datastore.Get(ctx, key)
+
+ if err == datastore.ErrNotFound {
+ return nil, errcode.ErrMissingInput.Wrap(err)
+ } else if err != nil {
+ return nil, errcode.ErrMessageKeyPersistenceGet.Wrap(err)
+ }
+
+ ds := &protocoltypes.DeviceChainKey{}
+ if err := ds.Unmarshal(dsBytes); err != nil {
+ return nil, errcode.ErrInvalidInput.Wrap(err)
+ }
+
+ return ds, nil
+}
+
+// IsChainKeyKnownForDevice returns true if the device chain key is known for the given group and device.
+func (s *secretStore) IsChainKeyKnownForDevice(ctx context.Context, groupPublicKey crypto.PubKey, devicePublicKey crypto.PubKey) (has bool) {
+ if s == nil {
+ return false
+ }
+
+ key, err := dsKeyForCurrentChainKey(groupPublicKey, devicePublicKey)
+ if err != nil {
+ return false
+ }
+
+ s.messageMutex.RLock()
+ defer s.messageMutex.RUnlock()
+
+ has, _ = s.datastore.Has(ctx, key)
+
+ return
+}
+
+// delPrecomputedKey deletes the message key in the cache namespace for the given group, device and counter.
+func (s *secretStore) delPrecomputedKey(ctx context.Context, groupPublicKey crypto.PubKey, devicePublicKey crypto.PubKey, msgCounter uint64) error {
+ if s == nil {
+ return errcode.ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
+ }
+
+ devicePublicKeyRaw, err := devicePublicKey.Raw()
+ if err != nil {
+ return errcode.ErrSerialization.Wrap(err)
+ }
+
+ groupPublicKeyRaw, err := groupPublicKey.Raw()
+ if err != nil {
+ return errcode.ErrSerialization.Wrap(err)
+ }
+
+ id := dsKeyForPrecomputedMessageKey(groupPublicKeyRaw, devicePublicKeyRaw, msgCounter)
+
+ err = s.datastore.Delete(ctx, id)
+
+ if err != nil {
+ return errcode.ErrMessageKeyPersistencePut.Wrap(err)
+ }
+
+ return nil
+}
+
+// postDecryptActions is called after a message has been decrypted.
+// It saves the message key from the cache namespace to find it quickly on subsequent read operations.
+// It derives the chain key in the cache namespace.
+func (s *secretStore) postDecryptActions(ctx context.Context, decryptionCtx *decryptionContext, groupPublicKey crypto.PubKey, ownPublicKey crypto.PubKey, msgHeaders *protocoltypes.MessageHeaders) error {
+ if s == nil {
+ return errcode.ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
+ }
+
+ // Message was newly decrypted, we can save the message key and derive
+ // future keys if necessary.
+ if decryptionCtx == nil || !decryptionCtx.newlyDecrypted {
+ return nil
+ }
+
+ var (
+ deviceChainKey *protocoltypes.DeviceChainKey
+ err error
+ )
+
+ devicePublicKey, err := crypto.UnmarshalEd25519PublicKey(msgHeaders.DevicePK)
+ if err != nil {
+ return errcode.ErrDeserialization.Wrap(err)
+ }
+
+ if err = s.putKeyForCID(ctx, decryptionCtx.cid, decryptionCtx.messageKey); err != nil {
+ return errcode.ErrInternal.Wrap(err)
+ }
+
+ if err = s.delPrecomputedKey(ctx, groupPublicKey, devicePublicKey, msgHeaders.Counter); err != nil {
+ return errcode.ErrInternal.Wrap(err)
+ }
+
+ if deviceChainKey, err = s.preComputeNextKey(ctx, groupPublicKey, devicePublicKey); err != nil {
+ return errcode.ErrInternal.Wrap(err)
+ }
+
+ // If the message was not emitted by the current Device we might need
+ // to update the current chain key
+ if ownPublicKey == nil || !ownPublicKey.Equals(devicePublicKey) {
+ if err = s.updateCurrentKey(ctx, groupPublicKey, devicePublicKey, deviceChainKey); err != nil {
+ return errcode.ErrInternal.Wrap(err)
+ }
+ }
+
+ return nil
+}
+
+func (s *secretStore) GetShareableChainKey(ctx context.Context, group *protocoltypes.Group, targetMemberPublicKey crypto.PubKey) ([]byte, error) {
+ deviceChainKey, err := s.getOwnDeviceChainKeyForGroup(ctx, group)
+ if err != nil {
+ return nil, errcode.ErrInvalidInput.Wrap(err)
+ }
+
+ privateMemberDevice, err := s.deviceKeystore.memberDeviceForGroup(group)
+ if err != nil {
+ return nil, errcode.ErrInvalidInput.Wrap(err)
+ }
+
+ encryptedDeviceChainKey, err := encryptDeviceChainKey(privateMemberDevice.device, targetMemberPublicKey, deviceChainKey, group)
+ if err != nil {
+ return nil, errcode.ErrCryptoEncrypt.Wrap(err)
+ }
+
+ return encryptedDeviceChainKey, nil
+}
+
+// getOwnDeviceChainKeyForGroup returns the device chain key for the current
+// device on a given group.
+// If the chain key has not been created yet, it will be generated and
+// registered.
+func (s *secretStore) getOwnDeviceChainKeyForGroup(ctx context.Context, group *protocoltypes.Group) (*protocoltypes.DeviceChainKey, error) {
+ if s == nil {
+ return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
+ }
+
+ if s.deviceKeystore == nil {
+ return nil, errcode.ErrCryptoSignature.Wrap(fmt.Errorf("message keystore is opened in read-only mode"))
+ }
+
+ md, err := s.deviceKeystore.memberDeviceForGroup(group)
+ if err != nil {
+ return nil, errcode.ErrInternal.Wrap(err)
+ }
+
+ groupPublicKey, err := group.GetPubKey()
+ if err != nil {
+ return nil, errcode.ErrDeserialization.Wrap(err)
+ }
+
+ s.messageMutex.Lock()
+ defer s.messageMutex.Unlock()
+
+ ds, err := s.getDeviceChainKeyForGroupAndDevice(ctx, groupPublicKey, md.Device())
+ if errcode.Is(err, errcode.ErrMissingInput) {
+ // If secret does not exist, create it
+ deviceChainKey, err := newDeviceChainKey()
+ if err != nil {
+ return nil, errcode.ErrCryptoKeyGeneration.Wrap(err)
+ }
+
+ if err = s.registerChainKey(ctx, group, md.Device(), deviceChainKey, true); err != nil {
+ return nil, errcode.ErrMessageKeyPersistencePut.Wrap(err)
+ }
+
+ return deviceChainKey, nil
+ }
+ if err != nil {
+ return nil, errcode.ErrMessageKeyPersistenceGet.Wrap(err)
+ }
+
+ return ds, nil
+}
+
+// RegisterChainKey registers a chain key for the given group and device.
+// If the device chain key is not from the current device, the function will
+// precompute and store in the cache namespace the next message keys.
+// It is the exported version of registerChainKey.
+func (s *secretStore) RegisterChainKey(ctx context.Context, group *protocoltypes.Group, senderDevicePublicKey crypto.PubKey, encryptedDeviceChainKey []byte) error {
+ if s == nil {
+ return errcode.ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
+ }
+
+ if s.deviceKeystore == nil {
+ return errcode.ErrCryptoSignature.Wrap(fmt.Errorf("message keystore is opened in read-only mode"))
+ }
+
+ localMemberDevice, err := s.deviceKeystore.memberDeviceForGroup(group)
+ if err != nil {
+ return errcode.ErrGroupMemberUnknownGroupID.Wrap(err)
+ }
+
+ deviceChainKey, err := decryptDeviceChainKey(encryptedDeviceChainKey, group, localMemberDevice.member, senderDevicePublicKey)
+ if err != nil {
+ return errcode.ErrCryptoDecrypt.Wrap(err)
+ }
+
+ hasSecretBeenSentByCurrentDevice := localMemberDevice.Member().Equals(senderDevicePublicKey)
+
+ return s.registerChainKey(ctx, group, senderDevicePublicKey, deviceChainKey, hasSecretBeenSentByCurrentDevice)
+}
+
+// registerChainKey registers a chain key for the given group and device.
+// If the chain key is not from the current device, the function will
+// precompute and store in the cache namespace the next message keys.
+func (s *secretStore) registerChainKey(ctx context.Context, group *protocoltypes.Group, devicePublicKey crypto.PubKey, deviceChainKey *protocoltypes.DeviceChainKey, isCurrentDeviceChainKey bool) error {
+ if s == nil {
+ return errcode.ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
+ }
+
+ groupPublicKey, err := group.GetPubKey()
+ if err != nil {
+ return errcode.ErrDeserialization.Wrap(err)
+ }
+
+ if _, err := s.getDeviceChainKeyForGroupAndDevice(ctx, groupPublicKey, devicePublicKey); err == nil {
+ // Device is already registered, ignore it
+ s.logger.Debug("device already registered in group",
+ logutil.PrivateBinary("devicePublicKey", logutil.CryptoKeyToBytes(devicePublicKey)),
+ logutil.PrivateBinary("groupPublicKey", logutil.CryptoKeyToBytes(groupPublicKey)),
+ )
+ return nil
+ }
+
+ s.logger.Debug("registering chain key",
+ logutil.PrivateBinary("devicePublicKey", logutil.CryptoKeyToBytes(devicePublicKey)),
+ logutil.PrivateBinary("groupPublicKey", logutil.CryptoKeyToBytes(groupPublicKey)),
+ )
+
+ // If own Device store key as is, no need to precompute future keys
+ if isCurrentDeviceChainKey {
+ if err := s.putDeviceChainKey(ctx, groupPublicKey, devicePublicKey, deviceChainKey); err != nil {
+ return errcode.ErrInternal.Wrap(err)
+ }
+
+ return nil
+ }
+
+ s.messageMutex.Lock()
+
+ if deviceChainKey, err = s.preComputeKeys(ctx, devicePublicKey, groupPublicKey, deviceChainKey); err != nil {
+ s.messageMutex.Unlock()
+ return errcode.ErrCryptoKeyGeneration.Wrap(err)
+ }
+
+ if err := s.putDeviceChainKey(ctx, groupPublicKey, devicePublicKey, deviceChainKey); err != nil {
+ s.messageMutex.Unlock()
+ return errcode.ErrInternal.Wrap(err)
+ }
+
+ s.messageMutex.Unlock()
+
+ devicePublicKeyBytes, err := devicePublicKey.Raw()
+ if err == nil {
+ if err := s.UpdateOutOfStoreGroupReferences(ctx, devicePublicKeyBytes, deviceChainKey.Counter, group); err != nil {
+ s.logger.Error("updating out of store group references failed", zap.Error(err))
+ }
+ }
+
+ return nil
+}
+
+// preComputeKeys precomputes the next m.preComputedKeysCount keys for the given device and group and put them in the cache namespace.
+func (s *secretStore) preComputeKeys(ctx context.Context, devicePublicKey crypto.PubKey, groupPublicKey crypto.PubKey, deviceChainKey *protocoltypes.DeviceChainKey) (*protocoltypes.DeviceChainKey, error) {
+ if s == nil {
+ return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
+ }
+
+ chainKeyValue := deviceChainKey.ChainKey
+ counter := deviceChainKey.Counter
+
+ groupPublicKeyBytes, err := groupPublicKey.Raw()
+ if err != nil {
+ return nil, errcode.ErrSerialization.Wrap(err)
+ }
+
+ knownDeviceChainKey, err := s.getDeviceChainKeyForGroupAndDevice(ctx, groupPublicKey, devicePublicKey)
+ if err != nil && !errcode.Is(err, errcode.ErrMissingInput) {
+ return nil, errcode.ErrInternal.Wrap(err)
+ }
+
+ var preComputedKeys []computedMessageKey
+ for i := 0; i < s.getPrecomputedKeyExpectedCount(); i++ {
+ counter++
+
+ knownMK, err := s.getPrecomputedMessageKey(ctx, groupPublicKey, devicePublicKey, counter)
+ if err != nil && !errcode.Is(err, errcode.ErrMissingInput) {
+ return nil, errcode.ErrInternal.Wrap(err)
+ }
+
+ newChainKeyValue, mk, err := deriveNextKeys(chainKeyValue, nil, groupPublicKeyBytes)
+ if err != nil {
+ return nil, errcode.TODO.Wrap(err)
+ }
+
+ chainKeyValue = newChainKeyValue
+
+ if knownMK != nil && knownDeviceChainKey != nil {
+ if knownDeviceChainKey.Counter != counter-1 {
+ continue
+ }
+ }
+
+ preComputedKeys = append(preComputedKeys, computedMessageKey{counter, &mk})
+ }
+
+ err = s.putPrecomputedKeys(ctx, groupPublicKey, devicePublicKey, preComputedKeys)
+ if err != nil {
+ return nil, errcode.TODO.Wrap(err)
+ }
+
+ return &protocoltypes.DeviceChainKey{
+ Counter: counter,
+ ChainKey: chainKeyValue,
+ }, nil
+}
+
+// getPrecomputedKeyExpectedCount returns the number of precomputed keys that
+// should be in the cache namespace of the keystore.
+func (s *secretStore) getPrecomputedKeyExpectedCount() int {
+ if s == nil || s.preComputedKeysCount < 0 {
+ return 0
+ }
+
+ return s.preComputedKeysCount
+}
+
+// preComputeNextKey precomputes the next key for the given group and device and adds it to the cache namespace.
+func (s *secretStore) preComputeNextKey(ctx context.Context, groupPublicKey crypto.PubKey, devicePublicKey crypto.PubKey) (*protocoltypes.DeviceChainKey, error) {
+ if s == nil {
+ return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
+ }
+
+ if devicePublicKey == nil {
+ return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("devicePublicKey cannot be nil"))
+ }
+
+ groupPublicKeyBytes, err := groupPublicKey.Raw()
+ if err != nil {
+ return nil, errcode.ErrSerialization.Wrap(err)
+ }
+
+ ds, err := s.getDeviceChainKeyForGroupAndDevice(ctx, groupPublicKey, devicePublicKey)
+ if err != nil {
+ return nil, errcode.ErrInternal.Wrap(err)
+ }
+
+ newCounter := ds.Counter + 1
+
+ // TODO: Salt?
+ newCK, mk, err := deriveNextKeys(ds.ChainKey, nil, groupPublicKeyBytes)
+ if err != nil {
+ return nil, errcode.TODO.Wrap(err)
+ }
+
+ err = s.putPrecomputedKeys(ctx, groupPublicKey, devicePublicKey, []computedMessageKey{{newCounter, &mk}})
+ if err != nil {
+ return nil, errcode.TODO.Wrap(err)
+ }
+
+ return &protocoltypes.DeviceChainKey{
+ Counter: newCounter,
+ ChainKey: newCK,
+ }, nil
+}
+
+// getPrecomputedMessageKey returns the precomputed message key put in the cache
+// namespace for the given group and device at the given counter.
+func (s *secretStore) getPrecomputedMessageKey(ctx context.Context, groupPublicKey crypto.PubKey, devicePublicKey crypto.PubKey, counter uint64) (*messageKey, error) {
+ if s == nil {
+ return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
+ }
+
+ deviceRaw, err := devicePublicKey.Raw()
+ if err != nil {
+ return nil, errcode.ErrSerialization.Wrap(err)
+ }
+
+ groupRaw, err := groupPublicKey.Raw()
+ if err != nil {
+ return nil, errcode.ErrSerialization.Wrap(err)
+ }
+
+ id := dsKeyForPrecomputedMessageKey(groupRaw, deviceRaw, counter)
+
+ key, err := s.datastore.Get(ctx, id)
+
+ if err == datastore.ErrNotFound {
+ return nil, errcode.ErrMissingInput.Wrap(fmt.Errorf("key for message does not exist in datastore"))
+ }
+ if err != nil {
+ return nil, errcode.ErrMessageKeyPersistenceGet.Wrap(err)
+ }
+
+ keyArray, err := cryptoutil.KeySliceToArray(key)
+ if err != nil {
+ return nil, errcode.ErrSerialization.Wrap(err)
+ }
+
+ return (*messageKey)(keyArray), nil
+}
+
+// putPrecomputedKeys puts the given precomputed keys in the cache namespace.
+// It will try to use a batch if the store supports it.
+func (s *secretStore) putPrecomputedKeys(ctx context.Context, groupPublicKey crypto.PubKey, devicePublicKey crypto.PubKey, preComputedMessageKeys []computedMessageKey) error {
+ if s == nil {
+ return errcode.ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
+ }
+
+ s.logger.Debug("putting precomputed keys", zap.Int("count", len(preComputedMessageKeys)))
+
+ if len(preComputedMessageKeys) == 0 {
+ return nil
+ }
+
+ deviceRaw, err := devicePublicKey.Raw()
+ if err != nil {
+ return errcode.ErrSerialization.Wrap(err)
+ }
+
+ groupRaw, err := groupPublicKey.Raw()
+ if err != nil {
+ return errcode.ErrSerialization.Wrap(err)
+ }
+
+ if batchedDatastore, ok := s.datastore.(datastore.BatchingFeature); ok {
+ batch, err := batchedDatastore.Batch(ctx)
+ if err == datastore.ErrBatchUnsupported {
+ return s.putPrecomputedKeysNonBatched(ctx, groupRaw, deviceRaw, preComputedMessageKeys)
+ }
+
+ return s.putPrecomputedKeysBatched(ctx, batch, groupRaw, deviceRaw, preComputedMessageKeys)
+ }
+
+ return s.putPrecomputedKeysNonBatched(ctx, groupRaw, deviceRaw, preComputedMessageKeys)
+}
+
+func (s *secretStore) putPrecomputedKeysBatched(ctx context.Context, batch datastore.Batch, groupRaw []byte, deviceRaw []byte, preComputedMessageKeys []computedMessageKey) error {
+ for _, preComputedKey := range preComputedMessageKeys {
+ id := dsKeyForPrecomputedMessageKey(groupRaw, deviceRaw, preComputedKey.counter)
+
+ if err := batch.Put(ctx, id, preComputedKey.messageKey[:]); err != nil {
+ return errcode.ErrMessageKeyPersistencePut.Wrap(err)
+ }
+ }
+
+ if err := batch.Commit(ctx); err != nil {
+ return errcode.ErrMessageKeyPersistencePut.Wrap(err)
+ }
+
+ return nil
+}
+
+func (s *secretStore) putPrecomputedKeysNonBatched(ctx context.Context, groupRaw []byte, deviceRaw []byte, preComputedMessageKeys []computedMessageKey) error {
+ for _, preComputedKey := range preComputedMessageKeys {
+ fmt.Println(">", groupRaw, deviceRaw, preComputedKey.counter)
+ id := dsKeyForPrecomputedMessageKey(groupRaw, deviceRaw, preComputedKey.counter)
+
+ if err := s.datastore.Put(ctx, id, preComputedKey.messageKey[:]); err != nil {
+ return errcode.ErrMessageKeyPersistencePut.Wrap(err)
+ }
+ }
+
+ return nil
+}
+
+// putKeyForCID puts the given message key in the datastore for a specified CID.
+func (s *secretStore) putKeyForCID(ctx context.Context, messageCID cid.Cid, messageKey *messageKey) error {
+ if s == nil {
+ return errcode.ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
+ }
+
+ if !messageCID.Defined() {
+ return nil
+ }
+
+ err := s.datastore.Put(ctx, dsKeyForMessageKeyByCID(messageCID), messageKey[:])
+ if err != nil {
+ return errcode.ErrMessageKeyPersistencePut.Wrap(err)
+ }
+
+ return nil
+}
+
+// OpenEnvelopePayload opens the payload of a message envelope and returns the
+// decrypted message in its EncryptedMessage form.
+// It also performs post decryption actions such as updating message key cache.
+func (s *secretStore) OpenEnvelopePayload(ctx context.Context, msgEnvelope *protocoltypes.MessageEnvelope, msgHeaders *protocoltypes.MessageHeaders, groupPublicKey crypto.PubKey, ownDevicePublicKey crypto.PubKey, msgCID cid.Cid) (*protocoltypes.EncryptedMessage, error) {
+ s.messageMutex.Lock()
+ defer s.messageMutex.Unlock()
+
+ msgBytes, decryptionCtx, err := s.openPayload(ctx, msgCID, groupPublicKey, msgEnvelope.Message, msgHeaders)
+ if err != nil {
+ return nil, errcode.ErrCryptoDecryptPayload.Wrap(err)
+ }
+
+ if err := s.postDecryptActions(ctx, decryptionCtx, groupPublicKey, ownDevicePublicKey, msgHeaders); err != nil {
+ return nil, errcode.TODO.Wrap(err)
+ }
+
+ var msg protocoltypes.EncryptedMessage
+ err = msg.Unmarshal(msgBytes)
+ if err != nil {
+ return nil, errcode.ErrDeserialization.Wrap(err)
+ }
+
+ return &msg, nil
+}
+
+// openPayload opens the payload of a message envelope and returns the
+// decrypted message.
+// It retrieves the message key from the keystore or the cache to decrypt
+// the message.
+func (s *secretStore) openPayload(ctx context.Context, msgCID cid.Cid, groupPublicKey crypto.PubKey, payload []byte, msgHeaders *protocoltypes.MessageHeaders) ([]byte, *decryptionContext, error) {
+ if s == nil {
+ return nil, nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
+ }
+
+ var (
+ err error
+ decryptionCtx = &decryptionContext{
+ cid: msgCID,
+ newlyDecrypted: true,
+ }
+ publicKey crypto.PubKey
+ )
+
+ if decryptionCtx.messageKey, err = s.getKeyForCID(ctx, msgCID); err == nil {
+ decryptionCtx.newlyDecrypted = false
+ } else {
+ publicKey, err = crypto.UnmarshalEd25519PublicKey(msgHeaders.DevicePK)
+ if err != nil {
+ return nil, nil, errcode.ErrDeserialization.Wrap(err)
+ }
+
+ decryptionCtx.messageKey, err = s.getPrecomputedMessageKey(ctx, groupPublicKey, publicKey, msgHeaders.Counter)
+ if err != nil {
+ return nil, nil, errcode.ErrCryptoDecrypt.Wrap(err)
+ }
+ }
+
+ return s.openPayloadWithMessageKey(decryptionCtx, publicKey, payload, msgHeaders)
+}
+
+// openPayloadWithMessageKey opens the payload of a message envelope with the
+// given key and returns the decrypted message with the decryptionContext
+// struct.
+func (s *secretStore) openPayloadWithMessageKey(decryptionCtx *decryptionContext, devicePublicKey crypto.PubKey, payload []byte, headers *protocoltypes.MessageHeaders) ([]byte, *decryptionContext, error) {
+ msg, ok := secretbox.Open(nil, payload, uint64AsNonce(headers.Counter), (*[32]byte)(decryptionCtx.messageKey))
+ if !ok {
+ return nil, nil, errcode.ErrCryptoDecrypt.Wrap(fmt.Errorf("secret box failed to open message payload"))
+ }
+
+ if decryptionCtx.newlyDecrypted {
+ if ok, err := devicePublicKey.Verify(msg, headers.Sig); !ok {
+ return nil, nil, errcode.ErrCryptoSignatureVerification.Wrap(fmt.Errorf("unable to verify message signature"))
+ } else if err != nil {
+ return nil, nil, errcode.ErrCryptoSignatureVerification.Wrap(err)
+ }
+ }
+
+ // Message was newly decrypted, we can save the message key and derive
+ // future keys if necessary.
+ return msg, decryptionCtx, nil
+}
+
+// getKeyForCID retrieves the message key for the given message CID.
+func (s *secretStore) getKeyForCID(ctx context.Context, msgCID cid.Cid) (*messageKey, error) {
+ if s == nil {
+ return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
+ }
+
+ if !msgCID.Defined() {
+ return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("undefined message CID"))
+ }
+
+ msgKey, err := s.datastore.Get(ctx, dsKeyForMessageKeyByCID(msgCID))
+
+ if err == datastore.ErrNotFound {
+ return nil, errcode.ErrInvalidInput.Wrap(err)
+ }
+
+ msgKeyArray, err := cryptoutil.KeySliceToArray(msgKey)
+ if err != nil {
+ return nil, errcode.ErrSerialization.Wrap(err)
+ }
+
+ return (*messageKey)(msgKeyArray), nil
+}
+
+// putDeviceChainKey stores the chain key for the given group and device.
+func (s *secretStore) putDeviceChainKey(ctx context.Context, groupPublicKey crypto.PubKey, devicePublicKey crypto.PubKey, deviceChainKey *protocoltypes.DeviceChainKey) error {
+ if s == nil {
+ return errcode.ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
+ }
+
+ deviceChainKeyBytes, err := deviceChainKey.Marshal()
+ if err != nil {
+ return errcode.ErrSerialization.Wrap(err)
+ }
+
+ datastoreKey, err := dsKeyForCurrentChainKey(groupPublicKey, devicePublicKey)
+ if err != nil {
+ return errcode.ErrSerialization.Wrap(err)
+ }
+
+ err = s.datastore.Put(ctx, datastoreKey, deviceChainKeyBytes)
+ if err != nil {
+ return errcode.ErrMessageKeyPersistencePut.Wrap(err)
+ }
+
+ return nil
+}
+
+// SealEnvelope encrypts the given payload and returns it as an envelope to be
+// published on the group's store.
+// It retrieves the device's chain key from the keystore to encrypt the payload
+// using symmetric encryption. The payload is signed using the device's long
+// term private key for the target group. It also updates the chain key and
+// stores the next message key in the cache.
+func (s *secretStore) SealEnvelope(ctx context.Context, group *protocoltypes.Group, messagePayload []byte) ([]byte, error) {
+ if s == nil {
+ return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
+ }
+
+ if s.deviceKeystore == nil {
+ return nil, errcode.ErrCryptoSignature.Wrap(fmt.Errorf("message keystore is opened in read-only mode"))
+ }
+
+ if group == nil {
+ return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("group cannot be nil"))
+ }
+
+ localMemberDevice, err := s.deviceKeystore.memberDeviceForGroup(group)
+ if err != nil {
+ return nil, errcode.ErrGroupMemberUnknownGroupID.Wrap(err)
+ }
+
+ groupPublicKey, err := group.GetPubKey()
+ if err != nil {
+ return nil, errcode.ErrDeserialization.Wrap(err)
+ }
+
+ s.messageMutex.Lock()
+ defer s.messageMutex.Unlock()
+
+ deviceChainKey, err := s.getDeviceChainKeyForGroupAndDevice(ctx, groupPublicKey, localMemberDevice.Device())
+ if err != nil {
+ return nil, errcode.ErrInternal.Wrap(fmt.Errorf("unable to get device chainkey: %w", err))
+ }
+
+ env, err := sealEnvelope(messagePayload, deviceChainKey, localMemberDevice.device, group)
+ if err != nil {
+ return nil, errcode.ErrCryptoEncrypt.Wrap(fmt.Errorf("unable to seal envelope: %w", err))
+ }
+
+ if err := s.deriveDeviceChainKey(ctx, group, localMemberDevice.Device()); err != nil {
+ return nil, errcode.ErrCryptoKeyGeneration.Wrap(err)
+ }
+
+ return env, nil
+}
+
+// deriveDeviceChainKey derives the chain key value from the current one.
+// It also updates the device chain key in the keystore.
+func (s *secretStore) deriveDeviceChainKey(ctx context.Context, group *protocoltypes.Group, devicePublicKey crypto.PubKey) error {
+ if s == nil {
+ return errcode.ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
+ }
+
+ if devicePublicKey == nil {
+ return errcode.ErrInvalidInput.Wrap(fmt.Errorf("device public key cannot be nil"))
+ }
+
+ groupPublicKey, err := group.GetPubKey()
+ if err != nil {
+ return errcode.ErrDeserialization.Wrap(err)
+ }
+
+ deviceChainKey, err := s.preComputeNextKey(ctx, groupPublicKey, devicePublicKey)
+ if err != nil {
+ return errcode.ErrCryptoKeyGeneration.Wrap(err)
+ }
+
+ if err = s.updateCurrentKey(ctx, groupPublicKey, devicePublicKey, deviceChainKey); err != nil {
+ return errcode.ErrCryptoKeyGeneration.Wrap(err)
+ }
+
+ return nil
+}
+
+// updateCurrentKey updates the current device chain key in the keystore if the
+// given device secret has a higher counter.
+func (s *secretStore) updateCurrentKey(ctx context.Context, groupPublicKey crypto.PubKey, devicePublicKey crypto.PubKey, deviceChainKey *protocoltypes.DeviceChainKey) error {
+ if s == nil {
+ return errcode.ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
+ }
+
+ currentDeviceChainKey, err := s.getDeviceChainKeyForGroupAndDevice(ctx, groupPublicKey, devicePublicKey)
+ if err != nil {
+ return errcode.ErrInternal.Wrap(err)
+ }
+
+ // FIXME: counter is set randomly and can overflow to 0
+ if deviceChainKey.Counter < currentDeviceChainKey.Counter {
+ return nil
+ }
+
+ if err = s.putDeviceChainKey(ctx, groupPublicKey, devicePublicKey, deviceChainKey); err != nil {
+ return errcode.ErrInternal.Wrap(err)
+ }
+
+ return nil
+}
+
+// OutOfStoreMessageOpen opens the given OutOfStoreMessage and returns the
+// decrypted payload.
+// The signature is verified against the given groupPublicKey.
+// It derives the next message key and stores it in the cache, but it doesn't
+// update the device's chain key.
+func (s *secretStore) OutOfStoreMessageOpen(ctx context.Context, envelope *protocoltypes.OutOfStoreMessage, groupPublicKey crypto.PubKey) ([]byte, bool, error) {
+ if s == nil {
+ return nil, false, errcode.ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
+ }
+
+ if envelope == nil {
+ return nil, false, errcode.ErrInvalidInput.Wrap(fmt.Errorf("envelope cannot be nil"))
+ }
+
+ if groupPublicKey == nil {
+ return nil, false, errcode.ErrInvalidInput.Wrap(fmt.Errorf("group public key cannot be nil"))
+ }
+
+ devicePublicKey, err := crypto.UnmarshalEd25519PublicKey(envelope.DevicePK)
+ if err != nil {
+ return nil, false, errcode.ErrDeserialization.Wrap(err)
+ }
+
+ c := cid.Undef
+ if len(envelope.CID) > 0 {
+ _, c, err = cid.CidFromBytes(envelope.CID)
+ if err != nil {
+ return nil, false, errcode.ErrDeserialization.Wrap(err)
+ }
+ }
+
+ s.messageMutex.Lock()
+ defer s.messageMutex.Unlock()
+
+ decryptionCtx := &decryptionContext{newlyDecrypted: true}
+ if decryptionCtx.messageKey, err = s.getKeyForCID(ctx, c); err == nil {
+ decryptionCtx.newlyDecrypted = false
+ } else {
+ decryptionCtx.messageKey, err = s.getPrecomputedMessageKey(ctx, groupPublicKey, devicePublicKey, envelope.Counter)
+ if err != nil {
+ return nil, false, errcode.ErrCryptoDecrypt.Wrap(err)
+ }
+ }
+
+ clear, decryptionCtx, err := s.openPayloadWithMessageKey(decryptionCtx, devicePublicKey, envelope.EncryptedPayload, &protocoltypes.MessageHeaders{
+ Counter: envelope.Counter,
+ DevicePK: envelope.DevicePK,
+ Sig: envelope.Sig,
+ })
+ if err != nil {
+ return nil, false, errcode.ErrCryptoDecrypt.Wrap(err)
+ }
+
+ if ok, err := devicePublicKey.Verify(clear, envelope.Sig); !ok {
+ return nil, false, errcode.ErrCryptoSignatureVerification.Wrap(fmt.Errorf("unable to verify message signature"))
+ } else if err != nil {
+ return nil, false, errcode.ErrCryptoSignatureVerification.Wrap(err)
+ }
+
+ if _, err = s.preComputeNextKey(ctx, groupPublicKey, devicePublicKey); err != nil {
+ return nil, false, errcode.ErrInternal.Wrap(err)
+ }
+
+ return clear, decryptionCtx.newlyDecrypted, nil
+}
+
+// OutOfStoreGetGroupPublicKeyByGroupReference returns the group public key
+// associated with the given out of store group reference (e.g. push
+// notification payload).
+func (s *secretStore) OutOfStoreGetGroupPublicKeyByGroupReference(ctx context.Context, ref []byte) (crypto.PubKey, error) {
+ s.messageMutex.RLock()
+ pk, err := s.datastore.Get(ctx, dsKeyForOutOfStoreMessageGroupHint(ref))
+ s.messageMutex.RUnlock()
+
+ if err != nil {
+ return nil, errcode.ErrNotFound.Wrap(err)
+ }
+
+ groupPublicKey, err := crypto.UnmarshalEd25519PublicKey(pk)
+ if err != nil {
+ return nil, errcode.ErrDeserialization.Wrap(err)
+ }
+
+ return groupPublicKey, nil
+}
+
+// UpdateOutOfStoreGroupReferences updates the out of store (e.g. push
+// notification payload) group references for the given devicePublicKey and
+// groupPublicKey in the keystore. It creates the references for the
+// given range [first + precomputeOutOfStoreGroupRefsCount] and
+// [first - precomputeOutOfStoreGroupRefsCount] and deletes out of range
+// references.
+func (s *secretStore) UpdateOutOfStoreGroupReferences(ctx context.Context, devicePublicKey []byte, first uint64, group *protocoltypes.Group) error {
+ s.messageMutex.Lock()
+ defer s.messageMutex.Unlock()
+
+ refsExisting := []uint64(nil)
+ refsToCreate := []uint64(nil)
+
+ currentFirst, currentLast, err := s.firstLastCachedGroupRefsForMember(ctx, devicePublicKey, group)
+ if err == nil {
+ for i := currentFirst; i != currentLast; i++ {
+ refsExisting = append(refsExisting, i)
+ }
+ }
+
+ // keep previous refs
+ last := first + s.precomputeOutOfStoreGroupRefsCount
+ first -= s.precomputeOutOfStoreGroupRefsCount
+ for i := first; i != last; i++ {
+ found := false
+
+ // Ignore refs that should be kept
+ for j := 0; j < len(refsExisting); j++ {
+ if refsExisting[j] == i {
+ refsExisting[j] = refsExisting[len(refsExisting)-1]
+ refsExisting = refsExisting[:len(refsExisting)-1]
+ found = true
+ break
+ }
+ }
+
+ if !found {
+ refsToCreate = append(refsToCreate, i)
+ }
+ }
+
+ // Remove useless old refs
+ for i := 0; i < len(refsExisting); i++ {
+ ref, err := createOutOfStoreGroupReference(group, devicePublicKey, refsExisting[i])
+ if err != nil {
+ s.logger.Error("creating existing out of store group reference failed", logutil.PrivateBinary("ref", ref), zap.Error(err))
+ continue
+ }
+
+ if err := s.datastore.Delete(ctx, dsKeyForOutOfStoreMessageGroupHint(ref)); err != nil {
+ s.logger.Error("deleting existing out of store group reference failed", logutil.PrivateBinary("ref", ref), zap.Error(err))
+ continue
+ }
+ }
+
+ // Add new refs
+ for i := 0; i < len(refsToCreate); i++ {
+ ref, err := createOutOfStoreGroupReference(group, devicePublicKey, refsToCreate[i])
+ if err != nil {
+ s.logger.Error("creating new out of store group reference failed", logutil.PrivateBinary("ref", ref), zap.Error(err))
+ continue
+ }
+
+ if err := s.datastore.Put(ctx, dsKeyForOutOfStoreMessageGroupHint(ref), group.GetPublicKey()); err != nil {
+ s.logger.Error("putting new out of store group reference failed", logutil.PrivateBinary("ref", ref), zap.Error(err))
+ continue
+ }
+ }
+
+ // Update first/last
+ if err := s.putFirstLastCachedGroupRefsForMember(ctx, first, last, devicePublicKey, group); err != nil {
+ s.logger.Error("putting first/last out of store group reference failed", zap.Error(err))
+ }
+
+ return nil
+}
+
+// firstLastCachedGroupRefsForMember returns the first and last cached group
+// references counter for the given devicePublicKey and group.
+func (s *secretStore) firstLastCachedGroupRefsForMember(ctx context.Context, devicePublicKeyBytes []byte, group *protocoltypes.Group) (uint64, uint64, error) {
+ key := dsKeyForOutOfStoreFirstLastCounters(group.GetPublicKey(), devicePublicKeyBytes)
+
+ // No mutex here
+ bytes, err := s.datastore.Get(ctx, key)
+ if err != nil {
+ return 0, 0, errcode.ErrDBRead.Wrap(err)
+ }
+
+ ret := protocoltypes.FirstLastCounters{}
+ if err := ret.Unmarshal(bytes); err != nil {
+ return 0, 0, errcode.ErrDeserialization.Wrap(err)
+ }
+
+ return ret.First, ret.Last, nil
+}
+
+// putFirstLastCachedGroupRefsForMember puts the first and last cached group
+// references counter for the given devicePK and groupPK.
+func (s *secretStore) putFirstLastCachedGroupRefsForMember(ctx context.Context, first uint64, last uint64, devicePublicKey []byte, group *protocoltypes.Group) error {
+ key := dsKeyForOutOfStoreFirstLastCounters(group.GetPublicKey(), devicePublicKey)
+
+ fistLast := protocoltypes.FirstLastCounters{
+ First: first,
+ Last: last,
+ }
+ bytes, err := fistLast.Marshal()
+ if err != nil {
+ return errcode.ErrSerialization.Wrap(err)
+ }
+
+ // Not mutex here
+ return s.datastore.Put(ctx, key, bytes)
+}
+
+func sealPayload(payload []byte, ds *protocoltypes.DeviceChainKey, devicePrivateKey crypto.PrivKey, g *protocoltypes.Group) ([]byte, []byte, error) {
+ var (
+ msgKey [32]byte
+ err error
+ )
+
+ sig, err := devicePrivateKey.Sign(payload)
+ if err != nil {
+ return nil, nil, errcode.ErrCryptoSignature.Wrap(err)
+ }
+
+ if _, msgKey, err = deriveNextKeys(ds.ChainKey, nil, g.GetPublicKey()); err != nil {
+ return nil, nil, errcode.ErrCryptoKeyGeneration.Wrap(err)
+ }
+
+ return secretbox.Seal(nil, payload, uint64AsNonce(ds.Counter+1), &msgKey), sig, nil
+}
+
+func sealEnvelope(messagePayload []byte, deviceChainKey *protocoltypes.DeviceChainKey, devicePrivateKey crypto.PrivKey, g *protocoltypes.Group) ([]byte, error) {
+ encryptedPayload, sig, err := sealPayload(messagePayload, deviceChainKey, devicePrivateKey, g)
+ if err != nil {
+ return nil, errcode.ErrCryptoEncrypt.Wrap(err)
+ }
+
+ devicePublicKeyRaw, err := devicePrivateKey.GetPublic().Raw()
+ if err != nil {
+ return nil, errcode.ErrSerialization.Wrap(err)
+ }
+
+ h := &protocoltypes.MessageHeaders{
+ Counter: deviceChainKey.Counter + 1,
+ DevicePK: devicePublicKeyRaw,
+ Sig: sig,
+ }
+
+ headers, err := proto.Marshal(h)
+ if err != nil {
+ return nil, errcode.ErrSerialization.Wrap(err)
+ }
+
+ nonce, err := cryptoutil.GenerateNonce()
+ if err != nil {
+ return nil, errcode.ErrCryptoNonceGeneration.Wrap(err)
+ }
+
+ encryptedHeaders := secretbox.Seal(nil, headers, nonce, g.GetSharedSecret())
+
+ env, err := proto.Marshal(&protocoltypes.MessageEnvelope{
+ MessageHeaders: encryptedHeaders,
+ Message: encryptedPayload,
+ Nonce: nonce[:],
+ })
+ if err != nil {
+ return nil, errcode.ErrSerialization.Wrap(err)
+ }
+
+ return env, nil
+}
+
+// nolint:unparam
+func deriveNextKeys(chainKeyValue []byte, salt []byte, groupID []byte) ([]byte, messageKey, error) {
+ var (
+ nextMsg [32]byte
+ err error
+ )
+
+ // Salt length must be equal to hash length (64 bytes for sha256)
+ hash := sha256.New
+
+ // Generate Pseudo Random Key using chainKeyValue as IKM and salt
+ prk := hkdf.Extract(hash, chainKeyValue, salt)
+ if len(prk) == 0 {
+ return nil, nextMsg, errcode.ErrInternal.Wrap(fmt.Errorf("unable to instantiate pseudo random key"))
+ }
+
+ // Expand using extracted prk and groupID as info (kind of namespace)
+ kdf := hkdf.Expand(hash, prk, groupID)
+
+ // Generate next KDF and message keys
+ nextCK, err := ioutil.ReadAll(io.LimitReader(kdf, 32))
+ if err != nil {
+ return nil, nextMsg, errcode.ErrCryptoKeyGeneration.Wrap(err)
+ }
+
+ nextMsgSlice, err := ioutil.ReadAll(io.LimitReader(kdf, 32))
+ if err != nil {
+ return nil, nextMsg, errcode.ErrCryptoKeyGeneration.Wrap(err)
+ }
+
+ copy(nextMsg[:], nextMsgSlice)
+
+ return nextCK, nextMsg, nil
+}
+
+func uint64AsNonce(val uint64) *[24]byte {
+ var nonce [24]byte
+
+ binary.BigEndian.PutUint64(nonce[:], val)
+
+ return &nonce
+}
diff --git a/pkg/secretstore/secret_store_messages_test.go b/pkg/secretstore/secret_store_messages_test.go
new file mode 100644
index 00000000..ef78d6fd
--- /dev/null
+++ b/pkg/secretstore/secret_store_messages_test.go
@@ -0,0 +1,244 @@
+package secretstore_test
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "path"
+ "testing"
+
+ cid "github.com/ipfs/go-cid"
+ "github.com/libp2p/go-libp2p/core/crypto"
+ "github.com/stretchr/testify/assert"
+
+ "berty.tech/weshnet"
+ "berty.tech/weshnet/pkg/protocoltypes"
+ "berty.tech/weshnet/pkg/secretstore"
+ "berty.tech/weshnet/pkg/testutil"
+)
+
+func addDummyMemberInMetadataStore(ctx context.Context, t testing.TB, ms *weshnet.MetadataStore, g *protocoltypes.Group, memberPK crypto.PubKey, join bool) crypto.PubKey {
+ t.Helper()
+
+ secretStore, err := secretstore.NewInMemSecretStore(nil)
+ assert.NoError(t, err)
+ assert.NotNil(t, secretStore)
+
+ md, err := secretStore.GetOwnMemberDeviceForGroup(g)
+ assert.NoError(t, err)
+
+ if join {
+ _, err = weshnet.MetadataStoreAddDeviceToGroup(ctx, ms, g, md)
+ assert.NoError(t, err)
+ }
+
+ deviceChainKeyToSend, err := secretStore.GetShareableChainKey(ctx, g, memberPK)
+ assert.NoError(t, err)
+
+ _, err = weshnet.MetadataStoreSendSecret(ctx, ms, g, md, memberPK, deviceChainKeyToSend)
+ assert.NoError(t, err)
+
+ return md.Device()
+}
+
+func Test_EncryptMessageEnvelope(t *testing.T) {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ g, _, err := weshnet.NewGroupMultiMember()
+ assert.NoError(t, err)
+
+ secretStore1, err := secretstore.NewInMemSecretStore(nil)
+ assert.NoError(t, err)
+ assert.NotNil(t, secretStore1)
+
+ t.Cleanup(func() {
+ _ = secretStore1.Close()
+ })
+
+ omd1, err := secretStore1.GetOwnMemberDeviceForGroup(g)
+ assert.NoError(t, err)
+
+ gc1 := weshnet.NewContextGroup(g, nil, nil, secretStore1, omd1, nil)
+
+ deviceChainKey1For1, err := secretStore1.GetShareableChainKey(ctx, g, gc1.MemberPubKey())
+ assert.NoError(t, err)
+
+ err = secretStore1.RegisterChainKey(ctx, g, gc1.DevicePubKey(), deviceChainKey1For1)
+ assert.NoError(t, err)
+
+ secretStore2, err := secretstore.NewInMemSecretStore(nil)
+ assert.NoError(t, err)
+ assert.NotNil(t, secretStore2)
+
+ t.Cleanup(func() {
+ _ = secretStore2.Close()
+ })
+
+ omd2, err := secretStore2.GetOwnMemberDeviceForGroup(g)
+ assert.NoError(t, err)
+
+ payloadRef1, err := (&protocoltypes.EncryptedMessage{Plaintext: []byte("Test payload 1")}).Marshal()
+ assert.NoError(t, err)
+
+ deviceChainKey1For2, err := secretStore1.GetShareableChainKey(ctx, g, omd2.Member())
+ assert.NoError(t, err)
+
+ deviceChainKey2For2, err := secretStore2.GetShareableChainKey(ctx, g, omd2.Member())
+ assert.NoError(t, err)
+
+ err = secretStore2.RegisterChainKey(ctx, g, omd2.Device(), deviceChainKey2For2)
+ assert.NoError(t, err)
+
+ err = secretStore2.RegisterChainKey(ctx, g, omd1.Device(), deviceChainKey1For2)
+ assert.NoError(t, err)
+
+ env1, err := secretStore1.SealEnvelope(ctx, g, payloadRef1)
+ assert.NoError(t, err)
+
+ headers, payloadClr1, err := openEnvelope(ctx, t, secretStore2, g, omd2.Device(), env1, cid.Undef)
+ assert.NoError(t, err)
+
+ devRaw, err := omd1.Device().Raw()
+ assert.Equal(t, headers.DevicePK, devRaw)
+
+ payloadClrlBytes, err := payloadClr1.Marshal()
+ assert.NoError(t, err)
+ assert.Equal(t, payloadRef1, payloadClrlBytes)
+}
+
+func testMessageKeyHolderCatchUp(t *testing.T, expectedNewDevices int, isSlow bool) {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ if isSlow {
+ testutil.FilterSpeed(t, testutil.Slow)
+ }
+
+ dir := path.Join(os.TempDir(), fmt.Sprintf("%d", os.Getpid()), "MessageKeyHolderCatchUp")
+ defer os.RemoveAll(dir)
+
+ peers, _, cleanup := weshnet.CreatePeersWithGroupTest(ctx, t, dir, 1, 1)
+ defer cleanup()
+
+ peer := peers[0]
+
+ secretStore1 := peer.SecretStore
+ ms1 := peer.GC.MetadataStore()
+
+ groupPublicKey, err := peer.GC.Group().GetPubKey()
+ assert.NoError(t, err)
+
+ devicesPK := make([]crypto.PubKey, expectedNewDevices)
+
+ for i := 0; i < expectedNewDevices; i++ {
+ devicesPK[i] = addDummyMemberInMetadataStore(ctx, t, ms1, peer.GC.Group(), peer.GC.MemberPubKey(), true)
+ }
+
+ for range peer.GC.FillMessageKeysHolderUsingPreviousData() {
+ }
+
+ for i, devicePublicKey := range devicesPK {
+ if !assert.True(t, secretStore1.IsChainKeyKnownForDevice(ctx, groupPublicKey, devicePublicKey)) {
+ t.Fatalf("failed at iteration %d", i)
+ }
+ }
+}
+
+func TestMessageKeyHolderCatchUp(t *testing.T) {
+ for _, testCase := range []struct {
+ expectedNewDevices int
+ slow bool
+ }{
+ {
+ expectedNewDevices: 2,
+ slow: false,
+ },
+ {
+ expectedNewDevices: 10,
+ slow: true,
+ },
+ } {
+ testMessageKeyHolderCatchUp(t, testCase.expectedNewDevices, testCase.slow)
+ }
+}
+
+func testMessageKeyHolderSubscription(t *testing.T, expectedNewDevices int, isSlow bool) {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ if isSlow {
+ testutil.FilterSpeed(t, testutil.Slow)
+ }
+
+ dir := path.Join(os.TempDir(), fmt.Sprintf("%d", os.Getpid()), "MessageKeyHolderSubscription")
+ defer os.RemoveAll(dir)
+
+ peers, groupPrivateKey, cleanup := weshnet.CreatePeersWithGroupTest(ctx, t, dir, 1, 1)
+ defer cleanup()
+
+ peer := peers[0]
+
+ secretStore1 := peer.SecretStore
+ ms1 := peer.GC.MetadataStore()
+
+ devicesPK := make([]crypto.PubKey, expectedNewDevices)
+
+ ch := peer.GC.FillMessageKeysHolderUsingNewData()
+
+ for i := 0; i < expectedNewDevices; i++ {
+ devicesPK[i] = addDummyMemberInMetadataStore(ctx, t, ms1, peer.GC.Group(), peer.GC.MemberPubKey(), true)
+ }
+
+ i := 0
+ for range ch {
+ i++
+ if i == expectedNewDevices {
+ break
+ }
+ }
+
+ for i, devicePublicKey := range devicesPK {
+ if !assert.True(t, secretStore1.IsChainKeyKnownForDevice(ctx, groupPrivateKey.GetPublic(), devicePublicKey)) {
+ t.Fatalf("failed at iteration %d", i)
+ }
+ }
+}
+
+func TestMessageKeyHolderSubscription(t *testing.T) {
+ for _, testCase := range []struct {
+ expectedNewDevices int
+ slow bool
+ }{
+ {
+ expectedNewDevices: 2,
+ slow: false,
+ },
+ {
+ expectedNewDevices: 10,
+ slow: true,
+ },
+ } {
+ testMessageKeyHolderSubscription(t, testCase.expectedNewDevices, testCase.slow)
+ }
+}
+
+// openEnvelope opens a MessageEnvelope and returns the decrypted message.
+// It performs all the necessary steps to decrypt the message.
+func openEnvelope(ctx context.Context, t testing.TB, secretStore secretstore.SecretStore, g *protocoltypes.Group, ownPK crypto.PubKey, data []byte, id cid.Cid) (*protocoltypes.MessageHeaders, *protocoltypes.EncryptedMessage, error) {
+ t.Helper()
+
+ assert.NotNil(t, secretStore)
+ assert.NotNil(t, g)
+
+ env, headers, err := secretStore.OpenEnvelopeHeaders(data, g)
+ assert.NoError(t, err)
+
+ gPK, err := g.GetPubKey()
+ assert.NoError(t, err)
+
+ msg, err := secretStore.OpenEnvelopePayload(ctx, env, headers, gPK, ownPK, id)
+ assert.NoError(t, err)
+
+ return headers, msg, nil
+}
diff --git a/pkg/secretstore/secret_store_test.go b/pkg/secretstore/secret_store_test.go
new file mode 100644
index 00000000..37ff1bf0
--- /dev/null
+++ b/pkg/secretstore/secret_store_test.go
@@ -0,0 +1,567 @@
+package secretstore
+
+import (
+ "context"
+ crand "crypto/rand"
+ "encoding/hex"
+ "fmt"
+ "testing"
+
+ "github.com/ipfs/go-cid"
+ "github.com/ipfs/go-datastore"
+ "github.com/libp2p/go-libp2p/core/crypto"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ "berty.tech/weshnet/pkg/protocoltypes"
+)
+
+func Test_PushGroupReferences(t *testing.T) {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ g, _, err := protocoltypes.NewGroupMultiMember()
+ require.NoError(t, err)
+
+ otherSecretStore, err := newInMemSecretStore(nil)
+ require.NoError(t, err)
+ t.Cleanup(func() {
+ _ = otherSecretStore.Close()
+ })
+
+ ownSecretStore, err := newInMemSecretStore(nil)
+ require.NoError(t, err)
+ t.Cleanup(func() {
+ _ = ownSecretStore.Close()
+ })
+
+ otherMemberDevice, err := otherSecretStore.GetOwnMemberDeviceForGroup(g)
+ require.NoError(t, err)
+
+ otherDevicePK, err := otherMemberDevice.Device().Raw()
+ require.NoError(t, err)
+
+ deviceChainKey, err := newDeviceChainKey()
+ require.NoError(t, err)
+
+ // test with the deviceChainKey counter
+ updateAndTestPushGroupReferences(ctx, ownSecretStore, otherDevicePK, deviceChainKey.Counter, g, t)
+
+ // do the same test with a new device chain key counter,
+ // so we can test if old references are deleted
+ updateAndTestPushGroupReferences(ctx, ownSecretStore, otherDevicePK, deviceChainKey.Counter+10, g, t)
+}
+
+func updateAndTestPushGroupReferences(ctx context.Context, secretStore *secretStore, devicePK []byte, counter uint64, g *protocoltypes.Group, t *testing.T) {
+ // update the push group references
+ err := secretStore.UpdateOutOfStoreGroupReferences(ctx, devicePK, counter, g)
+ require.NoError(t, err)
+
+ // test that the push group references are updated
+ // refs start counter - 100 to counter + 100
+ start := counter - PrecomputeOutOfStoreGroupRefsCount
+ end := counter + PrecomputeOutOfStoreGroupRefsCount
+
+ for i := start; i < end; i++ {
+ // compute the push group reference
+ pushGroupRef, err := createOutOfStoreGroupReference(g, devicePK, i)
+ require.NoError(t, err)
+
+ _, err = secretStore.OutOfStoreGetGroupPublicKeyByGroupReference(ctx, pushGroupRef)
+ require.NoError(t, err, fmt.Sprintf("started at %d, failed as %d", start, i))
+ }
+
+ // test boundary conditions
+
+ // before the start counter
+ {
+ before := counter - PrecomputeOutOfStoreGroupRefsCount - 1
+ pushGroupRef, err := createOutOfStoreGroupReference(g, devicePK, before)
+ require.NoError(t, err)
+ _, err = secretStore.OutOfStoreGetGroupPublicKeyByGroupReference(ctx, pushGroupRef)
+ require.Error(t, err)
+ }
+
+ // after the end counter
+ {
+ end := counter + PrecomputeOutOfStoreGroupRefsCount + 1
+ pushGroupRef, err := createOutOfStoreGroupReference(g, devicePK, end)
+ require.NoError(t, err)
+ _, err = secretStore.OutOfStoreGetGroupPublicKeyByGroupReference(ctx, pushGroupRef)
+ require.Error(t, err)
+ }
+}
+
+func Test_SealOutOfStoreMessageEnvelope_OpenOutOfStoreMessage(t *testing.T) {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ g, _, err := protocoltypes.NewGroupMultiMember()
+ require.NoError(t, err)
+
+ accUnrelated, err := newInMemSecretStore(nil)
+ require.NoError(t, err)
+ require.NotNil(t, accUnrelated)
+ t.Cleanup(func() {
+ _ = accUnrelated.Close()
+ })
+
+ err = accUnrelated.PutGroup(ctx, g)
+ require.NoError(t, err)
+
+ acc1, err := newInMemSecretStore(nil)
+ require.NoError(t, err)
+ t.Cleanup(func() {
+ _ = acc1.Close()
+ })
+
+ acc2, err := newInMemSecretStore(nil)
+ require.NoError(t, err)
+ t.Cleanup(func() {
+ _ = acc1.Close()
+ })
+
+ memberDevice1ForGroup, err := acc1.GetOwnMemberDeviceForGroup(g)
+ require.NoError(t, err)
+
+ memberDevice2ForGroup, err := acc2.GetOwnMemberDeviceForGroup(g)
+ require.NoError(t, err)
+
+ deviceChainKey1For2, err := acc1.GetShareableChainKey(ctx, g, memberDevice2ForGroup.Member())
+ require.NoError(t, err)
+
+ testPayload := []byte("test payload")
+
+ err = acc2.RegisterChainKey(ctx, g, memberDevice1ForGroup.Device(), deviceChainKey1For2)
+ require.NoError(t, err)
+
+ envEncrypted, err := acc1.SealEnvelope(ctx, g, testPayload)
+ require.NoError(t, err)
+
+ env, headers, err := ((*secretStore)(nil)).OpenEnvelopeHeaders(envEncrypted, g)
+ require.NoError(t, err)
+
+ outOfStoreEnv, err := (*secretStore)(nil).SealOutOfStoreMessageEnvelope(cid.Undef, env, headers, g)
+ require.NoError(t, err)
+
+ groupPublicKey, err := acc2.OutOfStoreGetGroupPublicKeyByGroupReference(ctx, outOfStoreEnv.GroupReference)
+ require.NoError(t, err)
+
+ outOfStoreMessage, err := accUnrelated.decryptOutOfStoreMessageEnv(ctx, outOfStoreEnv, groupPublicKey)
+ require.NoError(t, err)
+
+ payload, newlyDecrypted, err := acc2.OutOfStoreMessageOpen(ctx, outOfStoreMessage, groupPublicKey)
+ require.NoError(t, err)
+ require.True(t, newlyDecrypted)
+ require.Equal(t, testPayload, payload)
+}
+
+func Test_OutOfStoreDeserialize(t *testing.T) {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ secretStore1, err := NewSecretStore(datastore.NewMapDatastore(), nil)
+ require.NoError(t, err)
+
+ t.Cleanup(func() { _ = secretStore1.Close() })
+
+ secretStore2, err := NewSecretStore(datastore.NewMapDatastore(), nil)
+ require.NoError(t, err)
+
+ t.Cleanup(func() { _ = secretStore2.Close() })
+
+ group, _, err := protocoltypes.NewGroupMultiMember()
+ require.NoError(t, err)
+
+ require.NoError(t, secretStore1.PutGroup(ctx, group))
+ require.NoError(t, secretStore2.PutGroup(ctx, group))
+
+ memberDevice1, err := secretStore1.GetOwnMemberDeviceForGroup(group)
+ require.NoError(t, err)
+
+ memberDevice2, err := secretStore2.GetOwnMemberDeviceForGroup(group)
+ require.NoError(t, err)
+
+ chainKey1For2, err := secretStore1.GetShareableChainKey(ctx, group, memberDevice2.Member())
+ require.NoError(t, err)
+
+ chainKey2For1, err := secretStore2.GetShareableChainKey(ctx, group, memberDevice1.Member())
+ require.NoError(t, err)
+
+ require.NoError(t, secretStore1.RegisterChainKey(ctx, group, memberDevice2.Device(), chainKey2For1))
+ require.NoError(t, secretStore2.RegisterChainKey(ctx, group, memberDevice1.Device(), chainKey1For2))
+
+ testPayload := []byte("test payload")
+
+ env, err := secretStore1.SealEnvelope(ctx, group, testPayload)
+ require.NoError(t, err)
+
+ envHeaders, msgHeaders, err := secretStore1.OpenEnvelopeHeaders(env, group)
+ require.NoError(t, err)
+
+ dummyCID, err := cid.Parse("QmNR2n4zywCV61MeMLB6JwPueAPqheqpfiA4fLPMxouEmQ")
+ require.NoError(t, err)
+
+ device1Raw, err := memberDevice1.Device().Raw()
+ require.NoError(t, err)
+
+ outOfStoreMessageEnvelope, err := secretStore1.SealOutOfStoreMessageEnvelope(dummyCID, envHeaders, msgHeaders, group)
+ require.NoError(t, err)
+
+ outOfStoreMessageEnvelopeBytes, err := outOfStoreMessageEnvelope.Marshal()
+ require.NoError(t, err)
+
+ // Attempting to decrypt the message without a relay
+ {
+ openedOutOfStoreMessage, groupFound, clearPayload, alreadyDecrypted, err := secretStore2.OpenOutOfStoreMessage(ctx, outOfStoreMessageEnvelopeBytes)
+ require.NoError(t, err)
+
+ require.Equal(t, testPayload, clearPayload)
+ require.Equal(t, device1Raw, openedOutOfStoreMessage.DevicePK)
+ require.Equal(t, dummyCID.Bytes(), openedOutOfStoreMessage.CID)
+ require.Equal(t, group.PublicKey, groupFound.PublicKey)
+ require.False(t, alreadyDecrypted)
+ }
+}
+
+func Test_EncryptMessageEnvelopeAndDerive(t *testing.T) {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ g, _, err := protocoltypes.NewGroupMultiMember()
+ assert.NoError(t, err)
+
+ mkh1, err := newInMemSecretStore(nil)
+ assert.NoError(t, err)
+ t.Cleanup(func() {
+ _ = mkh1.Close()
+ })
+
+ mkh2, err := newInMemSecretStore(nil)
+ assert.NoError(t, err)
+ t.Cleanup(func() {
+ _ = mkh1.Close()
+ })
+
+ omd1, err := mkh1.GetOwnMemberDeviceForGroup(g)
+ assert.NoError(t, err)
+
+ omd2, err := mkh2.GetOwnMemberDeviceForGroup(g)
+ assert.NoError(t, err)
+
+ gPK, err := g.GetPubKey()
+ assert.NoError(t, err)
+
+ gc1DevicePubKey := omd1.Device()
+
+ ds1For1Encrypted, err := mkh1.GetShareableChainKey(ctx, g, omd1.Member())
+ assert.NoError(t, err)
+
+ ds1For2Encrypted, err := mkh1.GetShareableChainKey(ctx, g, omd2.Member())
+ assert.NoError(t, err)
+
+ ds2For2Encrypted, err := mkh2.GetShareableChainKey(ctx, g, omd2.Member())
+ assert.NoError(t, err)
+
+ err = mkh1.RegisterChainKey(ctx, g, omd1.Device(), ds1For1Encrypted)
+ assert.NoError(t, err)
+
+ err = mkh2.RegisterChainKey(ctx, g, omd2.Device(), ds2For2Encrypted)
+ assert.NoError(t, err)
+
+ err = mkh2.RegisterChainKey(ctx, g, omd1.Device(), ds1For2Encrypted)
+ assert.NoError(t, err)
+
+ ds1, err := mkh1.getOwnDeviceChainKeyForGroup(ctx, g)
+ assert.NoError(t, err)
+
+ initialCounter := ds1.Counter
+
+ for i := 0; i < 1000; i++ {
+ payloadRef, err := (&protocoltypes.EncryptedMessage{Plaintext: []byte("Test payload 1")}).Marshal()
+ assert.NoError(t, err)
+ envEncrypted, err := mkh1.SealEnvelope(ctx, g, payloadRef)
+ assert.NoError(t, err)
+
+ ds, err := mkh1.getDeviceChainKeyForGroupAndDevice(ctx, gPK, gc1DevicePubKey)
+ if !assert.NoError(t, err) {
+ t.Fatalf("failed at i = %d", i)
+ }
+ assert.Equal(t, ds.Counter, initialCounter+uint64(i+1))
+
+ env, headers, err := ((*secretStore)(nil)).OpenEnvelopeHeaders(envEncrypted, g)
+ if !assert.NoError(t, err) {
+ t.Fatalf("failed at i = %d", i)
+ }
+
+ payloadClr, err := mkh2.OpenEnvelopePayload(ctx, env, headers, gPK, omd2.Device(), cid.Undef)
+ if !assert.NoError(t, err) {
+ t.Fatalf("failed at i = %d", i)
+ }
+
+ if assert.NotNil(t, headers) && assert.NotNil(t, payloadClr) {
+ devRaw, err := omd1.Device().Raw()
+ assert.NoError(t, err)
+
+ assert.Equal(t, headers.DevicePK, devRaw)
+
+ payloadClrBytes, err := payloadClr.Marshal()
+ assert.NoError(t, err)
+ assert.Equal(t, payloadRef, payloadClrBytes)
+ } else {
+ break
+ }
+ }
+}
+
+func mustDeviceChainKey(t testing.TB) func(ds *protocoltypes.DeviceChainKey, err error) *protocoltypes.DeviceChainKey {
+ return func(ds *protocoltypes.DeviceChainKey, err error) *protocoltypes.DeviceChainKey {
+ t.Helper()
+
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ return ds
+ }
+}
+
+func mustMessageHeaders(t testing.TB, omd OwnMemberDevice, counter uint64, payload []byte) *protocoltypes.MessageHeaders {
+ t.Helper()
+
+ pkB, err := omd.Device().Raw()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ sig, err := omd.DeviceSign(payload)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ return &protocoltypes.MessageHeaders{
+ Counter: counter,
+ DevicePK: pkB,
+ Sig: sig,
+ }
+}
+
+func Test_EncryptMessagePayload(t *testing.T) {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ group, _, err := protocoltypes.NewGroupMultiMember()
+ assert.NoError(t, err)
+
+ mkh1, err := newInMemSecretStore(nil)
+ assert.NoError(t, err)
+ t.Cleanup(func() {
+ mkh1.Close()
+ })
+
+ mkh2, err := newInMemSecretStore(nil)
+ assert.NoError(t, err)
+ t.Cleanup(func() {
+ mkh2.Close()
+ })
+
+ omd1, err := mkh1.GetOwnMemberDeviceForGroup(group)
+ assert.NoError(t, err)
+
+ omd2, err := mkh2.GetOwnMemberDeviceForGroup(group)
+ assert.NoError(t, err)
+
+ encryptedDS1For1, err := mkh1.GetShareableChainKey(ctx, group, omd1.Member())
+ assert.NoError(t, err)
+
+ encryptedDS1For2, err := mkh1.GetShareableChainKey(ctx, group, omd2.Member())
+ assert.NoError(t, err)
+
+ encryptedDS2For2, err := mkh2.GetShareableChainKey(ctx, group, omd2.Member())
+ assert.NoError(t, err)
+
+ gc1DevicePubKey := omd1.Device()
+ gc2DevicePubKey := omd2.Device()
+
+ err = mkh1.RegisterChainKey(ctx, group, gc1DevicePubKey, encryptedDS1For1)
+ assert.NoError(t, err)
+
+ err = mkh2.RegisterChainKey(ctx, group, gc2DevicePubKey, encryptedDS2For2)
+ assert.NoError(t, err)
+
+ ds1, err := mkh1.getOwnDeviceChainKeyForGroup(ctx, group)
+ assert.NoError(t, err)
+
+ initialCounter := ds1.Counter
+ firstDeviceChainKey := append([]byte(nil), ds1.ChainKey...)
+
+ payloadRef1 := []byte("ok, this is the first test")
+ payloadRef2 := []byte("so, this is a second test")
+ payloadRef3 := []byte("this will be posted many times")
+
+ err = mkh2.RegisterChainKey(ctx, group, omd1.Device(), encryptedDS1For2)
+ assert.NoError(t, err)
+
+ gPK, err := group.GetPubKey()
+ assert.NoError(t, err)
+
+ assert.Equal(t, mustDeviceChainKey(t)(mkh1.getDeviceChainKeyForGroupAndDevice(ctx, gPK, omd1.Device())).ChainKey, firstDeviceChainKey)
+
+ payloadEnc1, _, err := sealPayload(payloadRef1, mustDeviceChainKey(t)(mkh1.getDeviceChainKeyForGroupAndDevice(ctx, gPK, omd1.Device())), omd1.(*ownMemberDevice).device, group)
+ assert.NoError(t, err)
+
+ // secret is derived by sealEnvelope
+ err = mkh1.deriveDeviceChainKey(ctx, group, omd1.Device())
+ assert.NoError(t, err)
+
+ assert.NotEqual(t, hex.EncodeToString(payloadRef1), hex.EncodeToString(payloadEnc1))
+
+ // Messages are encrypted with DeviceChainKey.Counter
+ // uint64 overflows to 0, which is the expected behaviour
+
+ // Test with a wrong counter value
+ payloadClr1, decryptInfo, err := mkh2.openPayload(ctx, cid.Undef, gPK, payloadEnc1, mustMessageHeaders(t, omd1, initialCounter+2, payloadRef1))
+ assert.Error(t, err)
+ assert.Nil(t, decryptInfo)
+ assert.Equal(t, "", string(payloadClr1))
+
+ // Test with a valid counter value, but no CID (so no cache)
+ payloadClr1, decryptInfo, err = mkh2.openPayload(ctx, cid.Undef, gPK, payloadEnc1, mustMessageHeaders(t, omd1, initialCounter+1, payloadRef1))
+ assert.NoError(t, err)
+ assert.Equal(t, string(payloadRef1), string(payloadClr1))
+
+ err = mkh2.postDecryptActions(ctx, decryptInfo, gPK, omd2.Device(), mustMessageHeaders(t, omd1, initialCounter+1, payloadRef1))
+ assert.NoError(t, err)
+
+ ds, err := mkh1.getDeviceChainKeyForGroupAndDevice(ctx, gPK, omd1.Device())
+ assert.NoError(t, err)
+
+ assert.Equal(t, ds.Counter, initialCounter+1)
+ assert.NotEqual(t, ds.ChainKey, firstDeviceChainKey)
+
+ payloadEnc2, _, err := sealPayload(payloadRef1, ds, omd1.(*ownMemberDevice).device, group)
+ assert.NoError(t, err)
+
+ err = mkh1.deriveDeviceChainKey(ctx, group, omd1.Device())
+ assert.NoError(t, err)
+
+ // Ensure that encrypted message is not the same as the first message
+ assert.NotEqual(t, hex.EncodeToString(payloadRef1), hex.EncodeToString(payloadEnc2))
+ assert.NotEqual(t, hex.EncodeToString(payloadEnc1), hex.EncodeToString(payloadEnc2))
+
+ payloadClr2, decryptInfo, err := mkh2.openPayload(ctx, cid.Undef, gPK, payloadEnc2, mustMessageHeaders(t, omd1, initialCounter+2, payloadRef1))
+ assert.NoError(t, err)
+
+ err = mkh2.postDecryptActions(ctx, decryptInfo, gPK, omd2.Device(), mustMessageHeaders(t, omd1, initialCounter+2, payloadRef1))
+ assert.NoError(t, err)
+
+ assert.Equal(t, string(payloadRef1), string(payloadClr2))
+
+ // Make sure that a message without a CID can't be decrypted twice
+ payloadClr2, decryptInfo, err = mkh2.openPayload(ctx, cid.Undef, gPK, payloadEnc2, mustMessageHeaders(t, omd1, initialCounter+1, payloadRef1))
+ assert.Error(t, err)
+ assert.Equal(t, "", string(payloadClr2))
+
+ ds, err = mkh1.getDeviceChainKeyForGroupAndDevice(ctx, gPK, omd1.Device())
+ assert.NoError(t, err)
+
+ // Make sure that a message a CID can be decrypted twice
+ payloadEnc3, _, err := sealPayload(payloadRef2, ds, omd1.(*ownMemberDevice).device, group)
+ assert.NoError(t, err)
+
+ err = mkh1.deriveDeviceChainKey(ctx, group, omd1.Device())
+ assert.NoError(t, err)
+
+ dummyCID1, err := cid.Parse("QmbdQXQh9B2bWZgZJqfbjNPV5jGN2owbQ3vjeYsaDaCDqU")
+ assert.NoError(t, err)
+
+ dummyCID2, err := cid.Parse("Qmf8oj9wbfu73prNAA1cRQVDqA52gD5B3ApnYQQjcjffH4")
+ assert.NoError(t, err)
+
+ // Not decrypted message yet, wrong counter value
+ payloadClr3, decryptInfo, err := mkh2.openPayload(ctx, dummyCID1, gPK, payloadEnc3, mustMessageHeaders(t, omd1, initialCounter+2, payloadRef2))
+ assert.Error(t, err)
+ assert.Equal(t, "", string(payloadClr3))
+
+ payloadClr3, decryptInfo, err = mkh2.openPayload(ctx, dummyCID1, gPK, payloadEnc3, mustMessageHeaders(t, omd1, initialCounter+3, payloadRef2))
+ assert.NoError(t, err)
+ assert.Equal(t, string(payloadRef2), string(payloadClr3))
+
+ err = mkh2.postDecryptActions(ctx, decryptInfo, gPK, omd2.Device(), mustMessageHeaders(t, omd1, initialCounter+3, payloadRef2))
+ assert.NoError(t, err)
+
+ payloadClr3, decryptInfo, err = mkh2.openPayload(ctx, dummyCID1, gPK, payloadEnc3, mustMessageHeaders(t, omd1, initialCounter+3, payloadRef2))
+ assert.NoError(t, err)
+ assert.Equal(t, string(payloadRef2), string(payloadClr3))
+
+ err = mkh2.postDecryptActions(ctx, decryptInfo, gPK, omd2.Device(), mustMessageHeaders(t, omd1, initialCounter+3, payloadRef2))
+ assert.NoError(t, err)
+
+ // Wrong CID
+ payloadClr3, decryptInfo, err = mkh2.openPayload(ctx, dummyCID2, gPK, payloadEnc3, mustMessageHeaders(t, omd1, initialCounter+3, payloadRef2))
+ assert.Error(t, err)
+ assert.Equal(t, "", string(payloadClr3))
+
+ // Reused CID, wrong counter value
+ payloadClr3, decryptInfo, err = mkh2.openPayload(ctx, dummyCID1, gPK, payloadEnc3, mustMessageHeaders(t, omd1, initialCounter+4, payloadRef2))
+ assert.Error(t, err)
+ assert.Equal(t, "", string(payloadClr3))
+
+ massExpected := uint64(200)
+
+ // Test appending 200 messages, to ensure new secrets are generated correctly
+ for i := uint64(0); i < massExpected; i++ {
+ ds, err = mkh1.getDeviceChainKeyForGroupAndDevice(ctx, gPK, omd1.Device())
+ assert.NoError(t, err)
+
+ payloadEnc, _, err := sealPayload(payloadRef3, ds, omd1.(*ownMemberDevice).device, group)
+ assert.NoError(t, err)
+
+ err = mkh1.deriveDeviceChainKey(ctx, group, omd1.Device())
+ assert.NoError(t, err)
+
+ ds, err = mkh1.getDeviceChainKeyForGroupAndDevice(ctx, gPK, omd1.Device())
+ assert.NoError(t, err)
+
+ counter := ds.Counter
+
+ payloadClr, decryptInfo, err := mkh2.openPayload(ctx, cid.Undef, gPK, payloadEnc, mustMessageHeaders(t, omd1, counter, payloadRef3))
+ if !assert.NoError(t, err) {
+ t.Fatalf("failed at i = %d", i)
+ }
+
+ err = mkh2.postDecryptActions(ctx, decryptInfo, gPK, omd2.Device(), mustMessageHeaders(t, omd1, counter, payloadRef3))
+ assert.NoError(t, err)
+
+ assert.Equal(t, string(payloadRef3), string(payloadClr))
+ }
+
+ ds, err = mkh1.getDeviceChainKeyForGroupAndDevice(ctx, gPK, omd1.Device())
+ assert.NoError(t, err)
+
+ assert.Equal(t, initialCounter+massExpected+3, ds.Counter)
+}
+
+func TestGetGroupForContact(t *testing.T) {
+ privateKey, _, err := crypto.GenerateEd25519Key(crand.Reader)
+ require.NoError(t, err)
+
+ group, err := getGroupForContact(privateKey)
+ require.NoError(t, err)
+
+ require.Equal(t, group.GroupType, protocoltypes.GroupTypeContact)
+ require.Equal(t, len(group.PublicKey), 32)
+ require.Equal(t, len(group.Secret), 32)
+}
+
+func TestGetKeysForGroupOfContact(t *testing.T) {
+ privateKey, _, err := crypto.GenerateEd25519Key(crand.Reader)
+ require.NoError(t, err)
+
+ groupPrivateKey, groupSecretPrivateKey, err := getKeysForGroupOfContact(privateKey)
+ require.NoError(t, err)
+
+ require.NotNil(t, groupPrivateKey)
+ require.NotNil(t, groupSecretPrivateKey)
+ require.False(t, groupPrivateKey.Equals(groupSecretPrivateKey))
+}
diff --git a/scenario_test.go b/scenario_test.go
index 372b946a..9abe0c6f 100644
--- a/scenario_test.go
+++ b/scenario_test.go
@@ -890,12 +890,13 @@ func sendMessageOnGroup(ctx context.Context, t *testing.T, senders, receivers []
func getAccountPubKey(t *testing.T, tp *weshnet.TestingProtocol) []byte {
t.Helper()
- tpSK, err := tp.Opts.DeviceKeystore.AccountPrivKey()
+ _, accMemberDevice, err := tp.Opts.SecretStore.GetGroupForAccount()
require.NoError(t, err)
- tpPK, err := tpSK.GetPublic().Raw()
+
+ publicKeyBytes, err := accMemberDevice.Member().Raw()
require.NoError(t, err)
- return tpPK
+ return publicKeyBytes
}
func getAccountB64PubKey(t *testing.T, tp *weshnet.TestingProtocol) string {
diff --git a/service.go b/service.go
index d934bf84..c86c9169 100644
--- a/service.go
+++ b/service.go
@@ -28,13 +28,13 @@ import (
"berty.tech/go-orbit-db/pubsub/directchannel"
"berty.tech/weshnet/internal/bertyversion"
"berty.tech/weshnet/internal/datastoreutil"
- "berty.tech/weshnet/pkg/bertypush"
"berty.tech/weshnet/pkg/bertyvcissuer"
"berty.tech/weshnet/pkg/cryptoutil"
"berty.tech/weshnet/pkg/errcode"
"berty.tech/weshnet/pkg/ipfsutil"
ipfs_mobile "berty.tech/weshnet/pkg/ipfsutil/mobile"
"berty.tech/weshnet/pkg/protocoltypes"
+ "berty.tech/weshnet/pkg/secretstore"
tinder "berty.tech/weshnet/pkg/tinder"
"berty.tech/weshnet/pkg/tyber"
)
@@ -57,18 +57,13 @@ type service struct {
logger *zap.Logger
ipfsCoreAPI ipfsutil.ExtendedCoreAPI
odb *WeshOrbitDB
- accountGroup *GroupContext
- deviceKeystore cryptoutil.DeviceKeystore
+ accountGroupCtx *GroupContext
openedGroups map[string]*GroupContext
lock sync.RWMutex
authSession atomic.Value
close func() error
startedAt time.Time
host host.Host
- groupDatastore *cryptoutil.GroupDatastore
- pushHandler bertypush.PushHandler
- accountCache ds.Batching
- messageKeystore *cryptoutil.MessageKeystore
pushClients map[string]*grpc.ClientConn
muPushClients sync.RWMutex
grpcInsecure bool
@@ -79,28 +74,28 @@ type service struct {
accountEventBus event.Bus
contactRequestsManager *contactRequestsManager
vcClient *bertyvcissuer.Client
+ secretStore secretstore.SecretStore
protocoltypes.UnimplementedProtocolServiceServer
}
// Opts contains optional configuration flags for building a new Client
type Opts struct {
- Logger *zap.Logger
- IpfsCoreAPI ipfsutil.ExtendedCoreAPI
- DeviceKeystore cryptoutil.DeviceKeystore
- DatastoreDir string
- RootDatastore ds.Batching
- GroupDatastore *cryptoutil.GroupDatastore
- AccountCache ds.Batching
- MessageKeystore *cryptoutil.MessageKeystore
- OrbitDB *WeshOrbitDB
- TinderService *tinder.Service
- Host host.Host
- PubSub *pubsub.PubSub
- GRPCInsecureMode bool
- LocalOnly bool
- close func() error
- PushKey *[cryptoutil.KeySize]byte
+ Logger *zap.Logger
+ IpfsCoreAPI ipfsutil.ExtendedCoreAPI
+ DatastoreDir string
+ RootDatastore ds.Batching
+ AccountCache ds.Batching
+ OrbitDB *WeshOrbitDB
+ TinderService *tinder.Service
+ Host host.Host
+ PubSub *pubsub.PubSub
+ GRPCInsecureMode bool
+ LocalOnly bool
+ close func() error
+ PushKey *[cryptoutil.KeySize]byte
+ SecretStore secretstore.SecretStore
+ OutOfStorePrivateKey *[cryptoutil.KeySize]byte
// These are used if OrbitDB is nil.
GroupMetadataStoreType string
@@ -114,22 +109,6 @@ func (opts *Opts) applyPushDefaults() error {
opts.applyDefaultsGetDatastore()
- if opts.GroupDatastore == nil {
- var err error
- opts.GroupDatastore, err = cryptoutil.NewGroupDatastore(opts.RootDatastore)
- if err != nil {
- return err
- }
- }
-
- if opts.AccountCache == nil {
- opts.AccountCache = datastoreutil.NewNamespacedDatastore(opts.RootDatastore, ds.NewKey(datastoreutil.NamespaceAccountCacheDatastore))
- }
-
- if opts.MessageKeystore == nil {
- opts.MessageKeystore = cryptoutil.NewMessageKeystore(datastoreutil.NewNamespacedDatastore(opts.RootDatastore, ds.NewKey(datastoreutil.NamespaceMessageKeystore)), opts.Logger)
- }
-
return nil
}
@@ -154,9 +133,16 @@ func (opts *Opts) applyDefaults(ctx context.Context) error {
return err
}
- if opts.DeviceKeystore == nil {
- ks := ipfsutil.NewDatastoreKeystore(datastoreutil.NewNamespacedDatastore(opts.RootDatastore, ds.NewKey(NamespaceDeviceKeystore)))
- opts.DeviceKeystore = cryptoutil.NewDeviceKeystore(ks, nil)
+ if opts.SecretStore == nil {
+ secretStore, err := secretstore.NewSecretStore(opts.RootDatastore, &secretstore.NewSecretStoreOptions{
+ Logger: opts.Logger,
+ OutOfStorePrivateKey: opts.OutOfStorePrivateKey,
+ })
+ if err != nil {
+ return errcode.ErrInternal.Wrap(err)
+ }
+
+ opts.SecretStore = secretStore
}
if opts.IpfsCoreAPI == nil {
@@ -207,9 +193,8 @@ func (opts *Opts) applyDefaults(ctx context.Context) error {
Directory: &orbitDirectory,
Logger: opts.Logger,
},
- Datastore: datastoreutil.NewNamespacedDatastore(opts.RootDatastore, ds.NewKey(NamespaceOrbitDBDatastore)),
- DeviceKeystore: opts.DeviceKeystore,
-
+ Datastore: datastoreutil.NewNamespacedDatastore(opts.RootDatastore, ds.NewKey(NamespaceOrbitDBDatastore)),
+ SecretStore: opts.SecretStore,
GroupMetadataStoreType: opts.GroupMetadataStoreType,
GroupMessageStoreType: opts.GroupMessageStoreType,
}
@@ -258,13 +243,13 @@ func NewService(opts Opts) (_ Service, err error) {
LocalOnly: &opts.LocalOnly,
}
- acc, err := opts.OrbitDB.openAccountGroup(ctx, dbOpts, opts.IpfsCoreAPI)
+ accountGroupCtx, err := opts.OrbitDB.openAccountGroup(ctx, dbOpts, opts.IpfsCoreAPI)
if err != nil {
cancel()
return nil, errcode.TODO.Wrap(err)
}
- opts.Logger.Debug("Opened account group", tyber.FormatStepLogFields(ctx, []tyber.Detail{{Name: "AccountGroup", Description: acc.group.String()}})...)
+ opts.Logger.Debug("Opened account group", tyber.FormatStepLogFields(ctx, []tyber.Detail{{Name: "AccountGroup", Description: accountGroupCtx.group.String()}})...)
var contactRequestsManager *contactRequestsManager
var swiper *Swiper
@@ -272,7 +257,7 @@ func NewService(opts Opts) (_ Service, err error) {
swiper = NewSwiper(opts.Logger, opts.TinderService, opts.OrbitDB.rotationInterval)
opts.Logger.Debug("Tinder swiper is enabled", tyber.FormatStepLogFields(ctx, []tyber.Detail{})...)
- if contactRequestsManager, err = newContactRequestsManager(swiper, acc.metadataStore, opts.IpfsCoreAPI, opts.Logger); err != nil {
+ if contactRequestsManager, err = newContactRequestsManager(swiper, accountGroupCtx.metadataStore, opts.IpfsCoreAPI, opts.Logger); err != nil {
cancel()
return nil, errcode.TODO.Wrap(err)
}
@@ -280,43 +265,26 @@ func NewService(opts Opts) (_ Service, err error) {
opts.Logger.Warn("No tinder driver provided, incoming and outgoing contact requests won't be enabled", tyber.FormatStepLogFields(ctx, []tyber.Detail{})...)
}
- if err := opts.GroupDatastore.Put(ctx, acc.Group()); err != nil {
+ if err := opts.SecretStore.PutGroup(ctx, accountGroupCtx.Group()); err != nil {
cancel()
return nil, errcode.ErrInternal.Wrap(fmt.Errorf("unable to add account group to group datastore, err: %w", err))
}
- pushHandler := (bertypush.PushHandler)(nil)
- if opts.PushKey != nil {
- pushHandler, err = bertypush.NewPushHandler(&bertypush.PushHandlerOpts{
- RootDatastore: opts.RootDatastore,
- PushKey: opts.PushKey,
- Logger: opts.Logger,
- })
- if err != nil {
- cancel()
- return nil, errcode.ErrInternal.Wrap(fmt.Errorf("unable to init push handler: %w", err))
- }
- }
-
s := &service{
- ctx: ctx,
- ctxCancel: cancel,
- host: opts.Host,
- ipfsCoreAPI: opts.IpfsCoreAPI,
- logger: opts.Logger,
- odb: opts.OrbitDB,
- deviceKeystore: opts.DeviceKeystore,
- close: opts.close,
- accountGroup: acc,
- swiper: swiper,
- startedAt: time.Now(),
- groupDatastore: opts.GroupDatastore,
+ ctx: ctx,
+ ctxCancel: cancel,
+ host: opts.Host,
+ ipfsCoreAPI: opts.IpfsCoreAPI,
+ logger: opts.Logger,
+ odb: opts.OrbitDB,
+ close: opts.close,
+ accountGroupCtx: accountGroupCtx,
+ swiper: swiper,
+ startedAt: time.Now(),
openedGroups: map[string]*GroupContext{
- string(acc.Group().PublicKey): acc,
+ string(accountGroupCtx.Group().PublicKey): accountGroupCtx,
},
- accountCache: opts.AccountCache,
- messageKeystore: opts.MessageKeystore,
- pushHandler: pushHandler,
+ secretStore: opts.SecretStore,
pushClients: make(map[string]*grpc.ClientConn),
grpcInsecure: opts.GRPCInsecureMode,
refreshprocess: make(map[string]context.CancelFunc),
@@ -349,7 +317,7 @@ func (s *service) Close() error {
}
for _, gc := range s.openedGroups {
- pk, subErr := crypto.UnmarshalEd25519PublicKey(gc.group.PublicKey)
+ pk, subErr := gc.group.GetPubKey()
if subErr != nil {
err = multierr.Append(err, subErr)
continue
diff --git a/service_group.go b/service_group.go
index adf2ea76..b6d2ccef 100644
--- a/service_group.go
+++ b/service_group.go
@@ -8,29 +8,24 @@ import (
"go.uber.org/zap"
"berty.tech/go-orbit-db/iface"
- "berty.tech/weshnet/pkg/cryptoutil"
"berty.tech/weshnet/pkg/errcode"
"berty.tech/weshnet/pkg/protocoltypes"
+ "berty.tech/weshnet/pkg/secretstore"
)
func (s *service) getContactGroup(key crypto.PubKey) (*protocoltypes.Group, error) {
- sk, err := s.deviceKeystore.ContactGroupPrivKey(key)
- if err != nil {
- return nil, errcode.ErrCryptoKeyGeneration.Wrap(err)
- }
-
- g, err := cryptoutil.GetGroupForContact(sk)
+ group, err := s.secretStore.GetGroupForContact(key)
if err != nil {
return nil, errcode.ErrOrbitDBOpen.Wrap(err)
}
- return g, nil
+ return group, nil
}
func (s *service) getGroupForPK(ctx context.Context, pk crypto.PubKey) (*protocoltypes.Group, error) {
- g, err := s.groupDatastore.Get(ctx, pk)
+ group, err := s.secretStore.FetchGroupByPublicKey(ctx, pk)
if err == nil {
- return g, nil
+ return group, nil
} else if !errcode.Is(err, errcode.ErrMissingMapKey) {
return nil, errcode.ErrInternal.Wrap(err)
}
@@ -40,13 +35,13 @@ func (s *service) getGroupForPK(ctx context.Context, pk crypto.PubKey) (*protoco
return nil, errcode.ErrGroupMissing
}
- if err = reindexGroupDatastore(ctx, s.groupDatastore, accountGroup.metadataStore, s.deviceKeystore); err != nil {
+ if err = reindexGroupDatastore(ctx, s.secretStore, accountGroup.metadataStore); err != nil {
return nil, errcode.TODO.Wrap(err)
}
- g, err = s.groupDatastore.Get(ctx, pk)
+ group, err = s.secretStore.FetchGroupByPublicKey(ctx, pk)
if err == nil {
- return g, nil
+ return group, nil
} else if errcode.Is(err, errcode.ErrMissingMapKey) {
return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("unknown group specified"))
}
@@ -77,7 +72,7 @@ func (s *service) deactivateGroup(pk crypto.PubKey) error {
delete(s.openedGroups, string(id))
if cg.group.GroupType == protocoltypes.GroupTypeAccount {
- s.accountGroup = nil
+ s.accountGroupCtx = nil
}
return nil
@@ -108,11 +103,11 @@ func (s *service) activateGroup(ctx context.Context, pk crypto.PubKey, localOnly
// nothing to get here, simply continue, open and activate the group
case protocoltypes.GroupTypeContact:
- if s.accountGroup == nil {
- return errcode.ErrGroupActivate.Wrap(fmt.Errorf("accountGroup is deactivated"))
+ if s.accountGroupCtx == nil {
+ return errcode.ErrGroupActivate.Wrap(fmt.Errorf("accountGroupCtx is deactivated"))
}
- contact := s.accountGroup.metadataStore.GetContactFromGroupPK(id)
+ contact := s.accountGroupCtx.metadataStore.GetContactFromGroupPK(id)
if contact != nil {
contactPK, err = contact.GetPubKey()
if err != nil {
@@ -121,16 +116,16 @@ func (s *service) activateGroup(ctx context.Context, pk crypto.PubKey, localOnly
}
case protocoltypes.GroupTypeAccount:
localOnly = true
- if s.accountGroup, err = s.odb.openAccountGroup(ctx, &iface.CreateDBOptions{EventBus: s.accountEventBus, LocalOnly: &localOnly}, s.ipfsCoreAPI); err != nil {
+ if s.accountGroupCtx, err = s.odb.openAccountGroup(ctx, &iface.CreateDBOptions{EventBus: s.accountEventBus, LocalOnly: &localOnly}, s.ipfsCoreAPI); err != nil {
return err
}
- s.openedGroups[string(id)] = s.accountGroup
+ s.openedGroups[string(id)] = s.accountGroupCtx
// reinitialize contactRequestsManager
if s.contactRequestsManager != nil {
s.contactRequestsManager.close()
- if s.contactRequestsManager, err = newContactRequestsManager(s.swiper, s.accountGroup.metadataStore, s.ipfsCoreAPI, s.logger); err != nil {
+ if s.contactRequestsManager, err = newContactRequestsManager(s.swiper, s.accountGroupCtx.metadataStore, s.ipfsCoreAPI, s.logger); err != nil {
return errcode.TODO.Wrap(err)
}
}
@@ -173,13 +168,13 @@ func (s *service) GetContextGroupForID(id []byte) (*GroupContext, error) {
return nil, errcode.ErrGroupUnknown
}
-func reindexGroupDatastore(ctx context.Context, gd *cryptoutil.GroupDatastore, m *MetadataStore, deviceKeystore cryptoutil.DeviceKeystore) error {
- if deviceKeystore == nil {
+func reindexGroupDatastore(ctx context.Context, secretStore secretstore.SecretStore, m *MetadataStore) error {
+ if secretStore == nil {
return errcode.ErrInvalidInput.Wrap(fmt.Errorf("missing device keystore"))
}
for _, g := range m.ListMultiMemberGroups() {
- if err := gd.Put(ctx, g); err != nil {
+ if err := secretStore.PutGroup(ctx, g); err != nil {
return errcode.ErrInternal.Wrap(err)
}
}
@@ -197,7 +192,12 @@ func reindexGroupDatastore(ctx context.Context, gd *cryptoutil.GroupDatastore, m
return errcode.TODO.Wrap(err)
}
- if err := gd.PutForContactPK(ctx, cPK, deviceKeystore); err != nil {
+ group, err := secretStore.GetGroupForContact(cPK)
+ if err != nil {
+ return errcode.ErrInternal.Wrap(err)
+ }
+
+ if err := secretStore.PutGroup(ctx, group); err != nil {
return errcode.ErrInternal.Wrap(err)
}
}
@@ -208,5 +208,5 @@ func reindexGroupDatastore(ctx context.Context, gd *cryptoutil.GroupDatastore, m
func (s *service) getAccountGroup() *GroupContext {
s.lock.Lock()
defer s.lock.Unlock()
- return s.accountGroup
+ return s.accountGroupCtx
}
diff --git a/store_message.go b/store_message.go
index f7bc7738..1d8935b5 100644
--- a/store_message.go
+++ b/store_message.go
@@ -13,7 +13,6 @@ import (
"github.com/libp2p/go-libp2p/core/event"
"github.com/libp2p/go-libp2p/p2p/host/eventbus"
"go.uber.org/zap"
- "golang.org/x/crypto/nacl/secretbox"
"golang.org/x/sync/semaphore"
ipfslog "berty.tech/go-ipfs-log"
@@ -24,11 +23,11 @@ import (
"berty.tech/go-orbit-db/stores"
"berty.tech/go-orbit-db/stores/basestore"
"berty.tech/go-orbit-db/stores/operation"
- "berty.tech/weshnet/pkg/cryptoutil"
"berty.tech/weshnet/pkg/errcode"
"berty.tech/weshnet/pkg/logutil"
"berty.tech/weshnet/pkg/protocoltypes"
"berty.tech/weshnet/pkg/pushtypes"
+ "berty.tech/weshnet/pkg/secretstore"
"berty.tech/weshnet/pkg/tyber"
)
@@ -41,10 +40,12 @@ type MessageStore struct {
groupCacheMessage event.Emitter
}
- devKS cryptoutil.DeviceKeystore
- mks *cryptoutil.MessageKeystore
- g *protocoltypes.Group
- logger *zap.Logger
+ secretStore secretstore.SecretStore
+ currentDevicePublicKey crypto.PubKey
+ currentDevicePublicKeyRaw []byte
+ group *protocoltypes.Group
+ groupPublicKey crypto.PubKey
+ logger *zap.Logger
deviceCaches map[string]*groupCache
muDeviceCaches sync.RWMutex
@@ -60,7 +61,7 @@ func (m *MessageStore) setLogger(l *zap.Logger) {
return
}
- m.logger = l.With(logutil.PrivateString("group-id", fmt.Sprintf("%.6s", base64.StdEncoding.EncodeToString(m.g.PublicKey))))
+ m.logger = l.With(logutil.PrivateString("group-id", fmt.Sprintf("%.6s", base64.StdEncoding.EncodeToString(m.group.PublicKey))))
}
func (m *MessageStore) openMessage(ctx context.Context, e ipfslog.Entry) (*protocoltypes.GroupMessageEvent, error) {
@@ -74,18 +75,17 @@ func (m *MessageStore) openMessage(ctx context.Context, e ipfslog.Entry) (*proto
return nil, err
}
- ownPK := crypto.PubKey(nil)
- md, inErr := m.devKS.MemberDeviceForGroup(m.g)
- if inErr == nil {
- ownPK = md.PrivateDevice().GetPublic()
+ env, headers, err := m.secretStore.OpenEnvelopeHeaders(op.GetValue(), m.group)
+ if err != nil {
+ return nil, errcode.ErrCryptoDecrypt.Wrap(err)
}
- env, headers, err := cryptoutil.OpenEnvelopeHeaders(op.GetValue(), m.g)
+ devicePublicKey, err := crypto.UnmarshalEd25519PublicKey(headers.DevicePK)
if err != nil {
- return nil, errcode.ErrCryptoDecrypt.Wrap(err)
+ return nil, errcode.ErrDeserialization.Wrap(err)
}
- if !m.mks.HasSecretForRawDevicePK(ctx, m.g.PublicKey, headers.DevicePK) {
+ if !m.secretStore.IsChainKeyKnownForDevice(ctx, m.groupPublicKey, devicePublicKey) {
if err := m.addToMessageQueue(ctx, e); err != nil {
m.logger.Error("unable to add message to cache", zap.Error(err))
}
@@ -93,19 +93,18 @@ func (m *MessageStore) openMessage(ctx context.Context, e ipfslog.Entry) (*proto
return nil, fmt.Errorf("no secret for device")
}
- return m.processMessage(ctx, ownPK, &messageItem{
+ return m.processMessage(ctx, &messageItem{
op: op,
env: env,
headers: headers,
- ownPK: ownPK,
hash: e.GetHash(),
})
}
type groupCache struct {
- self, hasSecret bool
- locker sync.Locker
- queue *priorityMessageQueue
+ self, hasKnownChainKey bool
+ locker sync.Locker
+ queue *priorityMessageQueue
}
func (m *MessageStore) CacheSizeForDevicePK(devicePK []byte) (size int, ok bool) {
@@ -121,7 +120,11 @@ func (m *MessageStore) CacheSizeForDevicePK(devicePK []byte) (size int, ok bool)
func (m *MessageStore) ProcessMessageQueueForDevicePK(ctx context.Context, devicePK []byte) {
m.muDeviceCaches.Lock()
if device, ok := m.deviceCaches[string(devicePK)]; ok {
- if device.hasSecret = m.mks.HasSecretForRawDevicePK(ctx, m.g.PublicKey, devicePK); !device.hasSecret {
+ devicePublicKey, errDevice := crypto.UnmarshalEd25519PublicKey(devicePK)
+
+ if errDevice != nil {
+ m.logger.Error("unable to process message, unmarshal of device pk failed", logutil.PrivateBinary("devicepk", devicePK))
+ } else if device.hasKnownChainKey = m.secretStore.IsChainKeyKnownForDevice(ctx, m.groupPublicKey, devicePublicKey); !device.hasKnownChainKey {
m.logger.Error("unable to process message, no secret found for device pk", logutil.PrivateBinary("devicepk", devicePK))
} else if next := device.queue.Next(); next != nil {
m.cmessage <- next
@@ -130,20 +133,20 @@ func (m *MessageStore) ProcessMessageQueueForDevicePK(ctx context.Context, devic
m.muDeviceCaches.Unlock()
}
-func (m *MessageStore) processMessage(ctx context.Context, ownPK crypto.PubKey, message *messageItem) (*protocoltypes.GroupMessageEvent, error) {
+func (m *MessageStore) processMessage(ctx context.Context, message *messageItem) (*protocoltypes.GroupMessageEvent, error) {
// process message
- msg, err := m.mks.OpenEnvelopePayload(ctx, message.env, message.headers, m.g, ownPK, message.hash)
+ msg, err := m.secretStore.OpenEnvelopePayload(ctx, message.env, message.headers, m.groupPublicKey, m.currentDevicePublicKey, message.hash)
if err != nil {
return nil, err
}
- err = m.mks.UpdatePushGroupReferences(ctx, message.headers.DevicePK, message.headers.Counter, m.g)
+ err = m.secretStore.UpdateOutOfStoreGroupReferences(ctx, message.headers.DevicePK, message.headers.Counter, m.group)
if err != nil {
m.logger.Error("unable to update push group references", zap.Error(err))
}
entry := message.op.GetEntry()
- eventContext := newEventContext(entry.GetHash(), entry.GetNext(), m.g)
+ eventContext := newEventContext(entry.GetHash(), entry.GetNext(), m.group)
return &protocoltypes.GroupMessageEvent{
EventContext: eventContext,
Headers: message.headers,
@@ -152,14 +155,6 @@ func (m *MessageStore) processMessage(ctx context.Context, ownPK crypto.PubKey,
}
func (m *MessageStore) processMessageLoop(ctx context.Context) {
- var ownPK crypto.PubKey
- var rawOwnPK []byte
- md, inErr := m.devKS.MemberDeviceForGroup(m.g)
- if inErr == nil {
- ownPK = md.PrivateDevice().GetPublic()
- rawOwnPK, _ = ownPK.Raw()
- }
-
semProcess := semaphore.NewWeighted(32)
for {
@@ -170,23 +165,29 @@ func (m *MessageStore) processMessageLoop(ctx context.Context) {
return
}
- devicepk := string(message.headers.DevicePK)
+ devicePublicKeyString := string(message.headers.DevicePK)
m.muDeviceCaches.Lock()
- device, ok := m.deviceCaches[devicepk]
+ device, ok := m.deviceCaches[devicePublicKeyString]
if !ok {
- hasSecret := m.mks.HasSecretForRawDevicePK(ctx, m.g.PublicKey, message.headers.DevicePK)
+ devicePublicKey, err := crypto.UnmarshalEd25519PublicKey(message.headers.DevicePK)
+ if err != nil {
+ m.logger.Error("unable to process message, unmarshal of device pk failed", logutil.PrivateBinary("devicepk", message.headers.DevicePK))
+ continue
+ }
+
+ hasSecret := m.secretStore.IsChainKeyKnownForDevice(ctx, m.groupPublicKey, devicePublicKey)
device = &groupCache{
- self: bytes.Equal(rawOwnPK, message.headers.DevicePK),
- queue: newPriorityMessageQueue(),
- locker: &sync.RWMutex{},
- hasSecret: hasSecret,
+ self: bytes.Equal(m.currentDevicePublicKeyRaw, message.headers.DevicePK),
+ queue: newPriorityMessageQueue(),
+ locker: &sync.RWMutex{},
+ hasKnownChainKey: hasSecret,
}
- m.deviceCaches[devicepk] = device
+ m.deviceCaches[devicePublicKeyString] = device
}
- // check for device secret, if unavailable add message to cache queue
- if !device.hasSecret {
+ // check for device chain key, if unavailable add message to cache queue
+ if !device.hasKnownChainKey {
device.queue.Add(message)
_ = m.emitters.groupCacheMessage.Emit(*message)
m.muDeviceCaches.Unlock()
@@ -205,7 +206,7 @@ func (m *MessageStore) processMessageLoop(ctx context.Context) {
defer semProcess.Release(1)
// process the message
- evt, err := m.processMessage(ctx, ownPK, message)
+ evt, err := m.processMessage(ctx, message)
if err != nil {
if errcode.Is(err, errcode.ErrCryptoDecryptPayload) {
// @FIXME(gfanton): this should not happen
@@ -245,13 +246,7 @@ func (m *MessageStore) addToMessageQueue(ctx context.Context, e ipfslog.Entry) e
return err
}
- ownPK := crypto.PubKey(nil)
- md, inErr := m.devKS.MemberDeviceForGroup(m.g)
- if inErr == nil {
- ownPK = md.PrivateDevice().GetPublic()
- }
-
- env, headers, err := cryptoutil.OpenEnvelopeHeaders(op.GetValue(), m.g)
+ env, headers, err := m.secretStore.OpenEnvelopeHeaders(op.GetValue(), m.group)
if err != nil {
return errcode.ErrCryptoDecrypt.Wrap(err)
}
@@ -260,7 +255,6 @@ func (m *MessageStore) addToMessageQueue(ctx context.Context, e ipfslog.Entry) e
hash: e.GetHash(),
env: env,
headers: headers,
- ownPK: ownPK,
op: op,
}
@@ -305,7 +299,7 @@ func (m *MessageStore) AddMessage(ctx context.Context, payload []byte) (operatio
ctx, newTrace := tyber.ContextWithTraceID(ctx)
if newTrace {
- m.logger.Debug("Sending message to group "+base64.RawURLEncoding.EncodeToString(m.g.PublicKey), tyber.FormatTraceLogFields(ctx)...)
+ m.logger.Debug("Sending message to group "+base64.RawURLEncoding.EncodeToString(m.group.PublicKey), tyber.FormatTraceLogFields(ctx)...)
}
m.logger.Debug(
@@ -318,15 +312,10 @@ func (m *MessageStore) AddMessage(ctx context.Context, payload []byte) (operatio
)...,
)
- md, err := m.devKS.MemberDeviceForGroup(m.g)
- if err != nil {
- return nil, errcode.ErrInternal.Wrap(err)
- }
-
- return messageStoreAddMessage(ctx, m.g, md, m, payload)
+ return messageStoreAddMessage(ctx, m.group, m, payload)
}
-func messageStoreAddMessage(ctx context.Context, g *protocoltypes.Group, md *cryptoutil.OwnMemberDevice, m *MessageStore, payload []byte) (operation.Operation, error) {
+func messageStoreAddMessage(ctx context.Context, g *protocoltypes.Group, m *MessageStore, payload []byte) (operation.Operation, error) {
msg, err := (&protocoltypes.EncryptedMessage{
Plaintext: payload,
ProtocolMetadata: &protocoltypes.ProtocolMetadata{},
@@ -335,7 +324,7 @@ func messageStoreAddMessage(ctx context.Context, g *protocoltypes.Group, md *cry
return nil, errcode.ErrInternal.Wrap(err)
}
- env, err := m.mks.SealEnvelope(ctx, g, md.PrivateDevice(), msg)
+ sealedEnvelope, err := m.secretStore.SealEnvelope(ctx, g, msg)
if err != nil {
return nil, errcode.ErrCryptoEncrypt.Wrap(err)
}
@@ -345,12 +334,12 @@ func messageStoreAddMessage(ctx context.Context, g *protocoltypes.Group, md *cry
ctx,
[]tyber.Detail{
{Name: "Cleartext size", Description: fmt.Sprintf("%d bytes", len(msg))},
- {Name: "Cyphertext size", Description: fmt.Sprintf("%d bytes", len(env))},
+ {Name: "Cyphertext size", Description: fmt.Sprintf("%d bytes", len(sealedEnvelope))},
},
)...,
)
- op := operation.NewOperation(nil, "ADD", env)
+ op := operation.NewOperation(nil, "ADD", sealedEnvelope)
e, err := m.AddOperation(ctx, op, nil)
if err != nil {
@@ -381,56 +370,69 @@ func constructorFactoryGroupMessage(s *WeshOrbitDB, logger *zap.Logger) iface.St
return nil, errcode.ErrInvalidInput.Wrap(err)
}
+ groupPublicKey, err := g.GetPubKey()
+ if err != nil {
+ return nil, errcode.ErrDeserialization.Wrap(err)
+ }
+
if options.EventBus == nil {
options.EventBus = eventbus.NewBus()
}
replication := false
- if s.deviceKeystore == nil {
+ store := &MessageStore{
+ eventBus: options.EventBus,
+ secretStore: s.secretStore,
+ cmessage: make(chan *messageItem),
+ group: g,
+ groupPublicKey: groupPublicKey,
+ logger: logger,
+ deviceCaches: make(map[string]*groupCache),
+ }
+
+ if s.replicationMode {
replication = true
} else {
- if _, err := s.deviceKeystore.MemberDeviceForGroup(g); errcode.Is(err, errcode.ErrInvalidInput) {
- replication = true
- } else if err != nil {
- return nil, errcode.ErrOrbitDBInit.Wrap(err)
+ currentMemberDevice, err := s.secretStore.GetOwnMemberDeviceForGroup(g)
+
+ if err != nil {
+ if errcode.Is(err, errcode.ErrInvalidInput) {
+ replication = true
+ } else {
+ return nil, errcode.ErrOrbitDBInit.Wrap(err)
+ }
+ } else {
+ store.currentDevicePublicKey = currentMemberDevice.Device()
+ store.currentDevicePublicKeyRaw, err = store.currentDevicePublicKey.Raw()
+ if err != nil {
+ return nil, errcode.ErrOrbitDBInit.Wrap(err)
+ }
}
}
- ctx, cancel := context.WithCancel(context.Background())
-
- store := &MessageStore{
- ctx: ctx,
- cancel: cancel,
- eventBus: options.EventBus,
- devKS: s.deviceKeystore,
- mks: s.messageKeystore,
- cmessage: make(chan *messageItem),
- g: g,
- logger: logger,
- deviceCaches: make(map[string]*groupCache),
- }
+ store.ctx, store.cancel = context.WithCancel(context.Background())
go func() {
- store.processMessageLoop(ctx)
- logger.Debug("store message process loop ended", zap.Error(ctx.Err()))
+ store.processMessageLoop(store.ctx)
+ logger.Debug("store message process loop ended", zap.Error(store.ctx.Err()))
}()
if store.emitters.groupMessage, err = store.eventBus.Emitter(new(protocoltypes.GroupMessageEvent)); err != nil {
- cancel()
+ store.cancel()
return nil, errcode.ErrOrbitDBInit.Wrap(err)
}
// for debug/test purpose
if store.emitters.groupCacheMessage, err = store.eventBus.Emitter(new(messageItem)); err != nil {
- cancel()
+ store.cancel()
return nil, errcode.ErrOrbitDBInit.Wrap(err)
}
options.Index = basestore.NewNoopIndex
if err := store.InitBaseStore(ipfs, identity, addr, options); err != nil {
- cancel()
+ store.cancel()
return nil, errcode.ErrOrbitDBInit.Wrap(err)
}
@@ -479,87 +481,43 @@ func constructorFactoryGroupMessage(s *WeshOrbitDB, logger *zap.Logger) iface.St
}
}
}
- }(ctx)
+ }(store.ctx)
return store, nil
}
}
-func (m *MessageStore) GetMessageByCID(c cid.Cid) (*protocoltypes.MessageEnvelope, *protocoltypes.MessageHeaders, error) {
+func (m *MessageStore) GetMessageByCID(c cid.Cid) (operation.Operation, error) {
logEntry, ok := m.OpLog().Get(c)
if !ok {
- return nil, nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("unable to find message entry"))
+ return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("unable to find message entry"))
}
op, err := operation.ParseOperation(logEntry)
if err != nil {
- return nil, nil, errcode.ErrDeserialization.Wrap(err)
+ return nil, errcode.ErrDeserialization.Wrap(err)
}
- env, headers, err := cryptoutil.OpenEnvelopeHeaders(op.GetValue(), m.g)
- if err != nil {
- return nil, nil, errcode.ErrDeserialization.Wrap(err)
- }
-
- return env, headers, nil
+ return op, nil
}
func (m *MessageStore) GetOutOfStoreMessageEnvelope(ctx context.Context, c cid.Cid) (*pushtypes.OutOfStoreMessageEnvelope, error) {
- env, headers, err := m.GetMessageByCID(c)
+ op, err := m.GetMessageByCID(c)
if err != nil {
return nil, errcode.ErrInvalidInput.Wrap(err)
}
- sealedMessageEnvelope, err := SealOutOfStoreMessageEnvelope(c, env, headers, m.g)
- if err != nil {
- return nil, errcode.ErrInternal.Wrap(err)
- }
-
- return sealedMessageEnvelope, nil
-}
-
-func SealOutOfStoreMessageEnvelope(id cid.Cid, env *protocoltypes.MessageEnvelope, headers *protocoltypes.MessageHeaders, g *protocoltypes.Group) (*pushtypes.OutOfStoreMessageEnvelope, error) {
- oosMessage := &protocoltypes.OutOfStoreMessage{
- CID: id.Bytes(),
- DevicePK: headers.DevicePK,
- Counter: headers.Counter,
- Sig: headers.Sig,
- EncryptedPayload: env.Message,
- Nonce: env.Nonce,
- }
-
- data, err := oosMessage.Marshal()
- if err != nil {
- return nil, errcode.ErrSerialization.Wrap(err)
- }
-
- nonce, err := cryptoutil.GenerateNonce()
- if err != nil {
- return nil, errcode.ErrCryptoNonceGeneration.Wrap(err)
- }
-
- secret, err := cryptoutil.KeySliceToArray(g.Secret)
+ env, headers, err := m.secretStore.OpenEnvelopeHeaders(op.GetValue(), m.group)
if err != nil {
- return nil, errcode.ErrSerialization.Wrap(err)
+ return nil, errcode.ErrDeserialization.Wrap(err)
}
- encryptedData := secretbox.Seal(nil, data, nonce, secret)
-
- groupPushSecret, err := cryptoutil.GetGroupPushSecret(g)
- if err != nil {
- return nil, errcode.ErrCryptoKeyGeneration.Wrap(err)
- }
-
- pushGroupRef, err := cryptoutil.CreatePushGroupReference(headers.DevicePK, headers.Counter, groupPushSecret)
+ sealedMessageEnvelope, err := m.secretStore.SealOutOfStoreMessageEnvelope(c, env, headers, m.group)
if err != nil {
- return nil, errcode.ErrCryptoKeyGeneration.Wrap(err)
+ return nil, errcode.ErrInternal.Wrap(err)
}
- return &pushtypes.OutOfStoreMessageEnvelope{
- Nonce: nonce[:],
- Box: encryptedData,
- GroupReference: pushGroupRef,
- }, nil
+ return sealedMessageEnvelope, nil
}
func (m *MessageStore) Close() error {
diff --git a/store_message_queue.go b/store_message_queue.go
index 2308b97d..6e3b30fb 100644
--- a/store_message_queue.go
+++ b/store_message_queue.go
@@ -5,7 +5,6 @@ import (
"sync"
"github.com/ipfs/go-cid"
- "github.com/libp2p/go-libp2p/core/crypto"
"berty.tech/go-orbit-db/stores/operation"
"berty.tech/weshnet/pkg/protocoltypes"
@@ -16,7 +15,6 @@ type messageItem struct {
op operation.Operation
env *protocoltypes.MessageEnvelope
headers *protocoltypes.MessageHeaders
- ownPK crypto.PubKey
hash cid.Cid
}
diff --git a/store_message_test.go b/store_message_test.go
index c78fd576..e3160033 100644
--- a/store_message_test.go
+++ b/store_message_test.go
@@ -42,11 +42,11 @@ func Test_AddMessage_ListMessages_manually_supplying_secrets(t *testing.T) {
defer cleanup()
dPK0 := peers[0].GC.DevicePubKey()
- ds0, err := peers[0].MKS.GetDeviceSecret(ctx, peers[0].GC.Group(), peers[0].DevKS)
+ ds0For1, err := peers[0].SecretStore.GetShareableChainKey(ctx, peers[0].GC.Group(), peers[1].GC.MemberPubKey())
require.NoError(t, err)
- require.NotNil(t, ds0)
+ require.NotNil(t, ds0For1)
- err = peers[1].MKS.RegisterChainKey(ctx, peers[0].GC.Group(), dPK0, ds0, false)
+ err = peers[1].SecretStore.RegisterChainKey(ctx, peers[0].GC.Group(), dPK0, ds0For1)
require.NoError(t, err)
_, err = peers[0].GC.MessageStore().AddMessage(ctx, testMsg1)
@@ -135,9 +135,9 @@ func Test_Add_Messages_To_Cache(t *testing.T) {
dPK0 := peers[0].GC.DevicePubKey()
dPK0Raw, err := dPK0.Raw()
require.NoError(t, err)
- ds0, err := peers[0].MKS.GetDeviceSecret(ctx, peers[0].GC.Group(), peers[0].DevKS)
+ ds0For1, err := peers[0].SecretStore.GetShareableChainKey(ctx, peers[0].GC.Group(), peers[1].GC.MemberPubKey())
require.NoError(t, err)
- require.NotNil(t, ds0)
+ require.NotNil(t, ds0For1)
cevent, err := peers[0].GC.MessageStore().EventBus().Subscribe(
new(protocoltypes.GroupMessageEvent), eventbus.BufSize(entriesCount))
@@ -186,7 +186,7 @@ func Test_Add_Messages_To_Cache(t *testing.T) {
require.True(t, ok)
require.Equal(t, entriesCount, size)
- err = peers[1].MKS.RegisterChainKey(ctx, peers[0].GC.Group(), dPK0, ds0, false)
+ err = peers[1].SecretStore.RegisterChainKey(ctx, peers[0].GC.Group(), dPK0, ds0For1)
require.NoError(t, err)
cevent, err = peers[1].GC.MessageStore().EventBus().Subscribe(
diff --git a/store_metadata.go b/store_metadata.go
index 5ed0af6f..eecd0b63 100644
--- a/store_metadata.go
+++ b/store_metadata.go
@@ -15,7 +15,6 @@ import (
"github.com/libp2p/go-libp2p/core/event"
"github.com/libp2p/go-libp2p/p2p/host/eventbus"
"go.uber.org/zap"
- "golang.org/x/crypto/nacl/box"
ipfslog "berty.tech/go-ipfs-log"
"berty.tech/go-ipfs-log/identityprovider"
@@ -25,10 +24,10 @@ import (
"berty.tech/go-orbit-db/stores"
"berty.tech/go-orbit-db/stores/basestore"
"berty.tech/go-orbit-db/stores/operation"
- "berty.tech/weshnet/pkg/cryptoutil"
"berty.tech/weshnet/pkg/errcode"
"berty.tech/weshnet/pkg/logutil"
"berty.tech/weshnet/pkg/protocoltypes"
+ "berty.tech/weshnet/pkg/secretstore"
"berty.tech/weshnet/pkg/tyber"
)
@@ -40,25 +39,26 @@ type MetadataStore struct {
metadataReceived event.Emitter
}
- g *protocoltypes.Group
- devKS cryptoutil.DeviceKeystore
- mks *cryptoutil.MessageKeystore
- logger *zap.Logger
+ group *protocoltypes.Group
+ memberDevice secretstore.OwnMemberDevice
+ devicePublicKeyRaw []byte
+ secretStore secretstore.SecretStore
+ logger *zap.Logger
ctx context.Context
cancel context.CancelFunc
}
func isMultiMemberGroup(m *MetadataStore) bool {
- return m.g.GroupType == protocoltypes.GroupTypeMultiMember
+ return m.group.GroupType == protocoltypes.GroupTypeMultiMember
}
func isAccountGroup(m *MetadataStore) bool {
- return m.g.GroupType == protocoltypes.GroupTypeAccount
+ return m.group.GroupType == protocoltypes.GroupTypeAccount
}
func isContactGroup(m *MetadataStore) bool {
- return m.g.GroupType == protocoltypes.GroupTypeContact
+ return m.group.GroupType == protocoltypes.GroupTypeContact
}
func (m *MetadataStore) typeChecker(types ...func(m *MetadataStore) bool) bool {
@@ -76,7 +76,7 @@ func (m *MetadataStore) setLogger(l *zap.Logger) {
return
}
- // m.logger = l.Named("store").With(logutil.PrivateString("group-id", fmt.Sprintf("%.6s", base64.StdEncoding.EncodeToString(m.g.PublicKey))))
+ // m.logger = l.Named("store").With(logutil.PrivateString("group-id", fmt.Sprintf("%.6s", base64.StdEncoding.EncodeToString(m.group.PublicKey))))
m.logger = l.Named("metastore")
if index, ok := m.Index().(loggable); ok {
@@ -105,7 +105,7 @@ func openMetadataEntry(log ipfslog.Log, e ipfslog.Entry, g *protocoltypes.Group)
// not used
// func (m *MetadataStore) openMetadataEntry(e ipfslog.Entry) (*protocoltypes.GroupMetadataEvent, proto.Message, error) {
-// return openMetadataEntry(m.OpLog(), e, m.g, m.devKS)
+// return openMetadataEntry(m.OpLog(), e, m.group, m.devKS)
// }
// FIXME: use iterator instead to reduce resource usage (require go-ipfs-log improvements)
@@ -122,7 +122,7 @@ func (m *MetadataStore) ListEvents(ctx context.Context, since, until []byte, rev
entries,
reverse,
func(entry ipliface.IPFSLogEntry) {
- event, _, err := openMetadataEntry(m.OpLog(), entry, m.g)
+ event, _, err := openMetadataEntry(m.OpLog(), entry, m.group)
if err != nil {
m.logger.Error("unable to open metadata event", zap.Error(err))
} else {
@@ -139,31 +139,31 @@ func (m *MetadataStore) ListEvents(ctx context.Context, since, until []byte, rev
}
func (m *MetadataStore) AddDeviceToGroup(ctx context.Context) (operation.Operation, error) {
- md, err := m.devKS.MemberDeviceForGroup(m.g)
+ md, err := m.secretStore.GetOwnMemberDeviceForGroup(m.group)
if err != nil {
return nil, errcode.ErrInternal.Wrap(err)
}
- return MetadataStoreAddDeviceToGroup(ctx, m, m.g, md)
+ return MetadataStoreAddDeviceToGroup(ctx, m, m.group, md)
}
-func MetadataStoreAddDeviceToGroup(ctx context.Context, m *MetadataStore, g *protocoltypes.Group, md *cryptoutil.OwnMemberDevice) (operation.Operation, error) {
- device, err := md.PrivateDevice().GetPublic().Raw()
+func MetadataStoreAddDeviceToGroup(ctx context.Context, m *MetadataStore, g *protocoltypes.Group, md secretstore.OwnMemberDevice) (operation.Operation, error) {
+ device, err := md.Device().Raw()
if err != nil {
return nil, errcode.ErrSerialization.Wrap(err)
}
- member, err := md.PrivateMember().GetPublic().Raw()
+ member, err := md.Member().Raw()
if err != nil {
return nil, errcode.ErrSerialization.Wrap(err)
}
- k, err := m.GetMemberByDevice(md.PrivateDevice().GetPublic())
+ k, err := m.GetMemberByDevice(md.Device())
if err == nil && k != nil {
return nil, nil
}
- memberSig, err := md.PrivateMember().Sign(device)
+ memberSig, err := md.MemberSign(device)
if err != nil {
return nil, errcode.ErrCryptoSignature.Wrap(err)
}
@@ -174,7 +174,7 @@ func MetadataStoreAddDeviceToGroup(ctx context.Context, m *MetadataStore, g *pro
MemberSig: memberSig,
}
- sig, err := signProto(event, md.PrivateDevice())
+ sig, err := signProtoWithDevice(event, md)
if err != nil {
return nil, errcode.ErrCryptoSignature.Wrap(err)
}
@@ -185,11 +185,6 @@ func MetadataStoreAddDeviceToGroup(ctx context.Context, m *MetadataStore, g *pro
}
func (m *MetadataStore) SendSecret(ctx context.Context, memberPK crypto.PubKey) (operation.Operation, error) {
- md, err := m.devKS.MemberDeviceForGroup(m.g)
- if err != nil {
- return nil, errcode.ErrInternal.Wrap(err)
- }
-
ok, err := m.Index().(*metadataStoreIndex).areSecretsAlreadySent(memberPK)
if err != nil {
return nil, errcode.ErrInvalidInput.Wrap(err)
@@ -203,21 +198,16 @@ func (m *MetadataStore) SendSecret(ctx context.Context, memberPK crypto.PubKey)
m.logger.Warn("sending secret to an unknown group member")
}
- ds, err := m.mks.GetDeviceSecret(ctx, m.g, m.devKS)
+ encryptedSecret, err := m.secretStore.GetShareableChainKey(ctx, m.group, memberPK)
if err != nil {
- return nil, errcode.ErrInvalidInput.Wrap(err)
+ return nil, errcode.ErrCryptoEncrypt.Wrap(err)
}
- return MetadataStoreSendSecret(ctx, m, m.g, md, memberPK, ds)
+ return MetadataStoreSendSecret(ctx, m, m.group, m.memberDevice, memberPK, encryptedSecret)
}
-func MetadataStoreSendSecret(ctx context.Context, m *MetadataStore, g *protocoltypes.Group, md *cryptoutil.OwnMemberDevice, memberPK crypto.PubKey, ds *protocoltypes.DeviceSecret) (operation.Operation, error) {
- payload, err := newSecretEntryPayload(md.PrivateDevice(), memberPK, ds, g)
- if err != nil {
- return nil, errcode.ErrInternal.Wrap(err)
- }
-
- devicePKRaw, err := md.PrivateDevice().GetPublic().Raw()
+func MetadataStoreSendSecret(ctx context.Context, m *MetadataStore, g *protocoltypes.Group, md secretstore.OwnMemberDevice, memberPK crypto.PubKey, encryptedSecret []byte) (operation.Operation, error) {
+ devicePKRaw, err := md.Device().Raw()
if err != nil {
return nil, errcode.ErrSerialization.Wrap(err)
}
@@ -227,18 +217,18 @@ func MetadataStoreSendSecret(ctx context.Context, m *MetadataStore, g *protocolt
return nil, errcode.ErrSerialization.Wrap(err)
}
- event := &protocoltypes.GroupAddDeviceSecret{
+ event := &protocoltypes.GroupAddDeviceChainKey{
DevicePK: devicePKRaw,
DestMemberPK: memberPKRaw,
- Payload: payload,
+ Payload: encryptedSecret,
}
- sig, err := signProto(event, md.PrivateDevice())
+ sig, err := signProtoWithDevice(event, md)
if err != nil {
return nil, errcode.ErrCryptoSignature.Wrap(err)
}
- return metadataStoreAddEvent(ctx, m, g, protocoltypes.EventTypeGroupDeviceSecretAdded, event, sig)
+ return metadataStoreAddEvent(ctx, m, g, protocoltypes.EventTypeGroupDeviceChainKeyAdded, event, sig)
}
func (m *MetadataStore) ClaimGroupOwnership(ctx context.Context, groupSK crypto.PrivKey) (operation.Operation, error) {
@@ -246,29 +236,33 @@ func (m *MetadataStore) ClaimGroupOwnership(ctx context.Context, groupSK crypto.
return nil, errcode.ErrGroupInvalidType
}
- md, err := m.devKS.MemberDeviceForGroup(m.g)
- if err != nil {
- return nil, errcode.ErrInternal.Wrap(err)
+ event := &protocoltypes.MultiMemberInitialMember{
+ MemberPK: m.devicePublicKeyRaw,
}
- memberPK, err := md.PrivateMember().GetPublic().Raw()
+ sig, err := signProtoWithPrivateKey(event, groupSK)
if err != nil {
- return nil, errcode.ErrSerialization.Wrap(err)
+ return nil, errcode.ErrCryptoSignature.Wrap(err)
}
- event := &protocoltypes.MultiMemberInitialMember{
- MemberPK: memberPK,
+ return metadataStoreAddEvent(ctx, m, m.group, protocoltypes.EventTypeMultiMemberGroupInitialMemberAnnounced, event, sig)
+}
+
+func signProtoWithDevice(message proto.Message, memberDevice secretstore.OwnMemberDevice) ([]byte, error) {
+ data, err := proto.Marshal(message)
+ if err != nil {
+ return nil, errcode.ErrSerialization.Wrap(err)
}
- sig, err := signProto(event, groupSK)
+ sig, err := memberDevice.DeviceSign(data)
if err != nil {
return nil, errcode.ErrCryptoSignature.Wrap(err)
}
- return metadataStoreAddEvent(ctx, m, m.g, protocoltypes.EventTypeMultiMemberGroupInitialMemberAnnounced, event, sig)
+ return sig, nil
}
-func signProto(message proto.Message, sk crypto.PrivKey) ([]byte, error) {
+func signProtoWithPrivateKey(message proto.Message, sk crypto.PrivKey) ([]byte, error) {
data, err := proto.Marshal(message)
if err != nil {
return nil, errcode.ErrSerialization.Wrap(err)
@@ -348,20 +342,14 @@ func (m *MetadataStore) GetIncomingContactRequestsStatus() (bool, *protocoltypes
enabled := m.Index().(*metadataStoreIndex).contactRequestsEnabled()
seed := m.Index().(*metadataStoreIndex).contactRequestsSeed()
- md, err := m.devKS.MemberDeviceForGroup(m.g)
- if err != nil {
- m.logger.Error("unable to get member device for group", zap.Error(err))
- return enabled, nil
- }
-
- pkBytes, err := md.PrivateMember().GetPublic().Raw()
+ rawMemberDevice, err := m.memberDevice.Member().Raw()
if err != nil {
m.logger.Error("unable to serialize member public key", zap.Error(err))
return enabled, nil
}
contactRef := &protocoltypes.ShareableContact{
- PK: pkBytes,
+ PK: rawMemberDevice,
PublicRendezvousSeed: seed,
}
@@ -572,7 +560,7 @@ func (m *MetadataStore) ContactRequestReferenceReset(ctx context.Context) (opera
func (m *MetadataStore) ContactRequestOutgoingEnqueue(ctx context.Context, contact *protocoltypes.ShareableContact, ownMetadata []byte) (operation.Operation, error) {
ctx, _ = tyber.ContextWithTraceID(ctx)
- b64GroupPK := base64.RawURLEncoding.EncodeToString(m.g.PublicKey)
+ b64GroupPK := base64.RawURLEncoding.EncodeToString(m.group.PublicKey)
m.logger.Debug("Enqueuing contact request", tyber.FormatStepLogFields(ctx, []tyber.Detail{{Name: "GroupPK", Description: fmt.Sprint(b64GroupPK)}})...)
if !m.typeChecker(isAccountGroup) {
@@ -583,12 +571,8 @@ func (m *MetadataStore) ContactRequestOutgoingEnqueue(ctx context.Context, conta
return nil, errcode.ErrInvalidInput.Wrap(err)
}
- accSK, err := m.devKS.AccountPrivKey()
- if err != nil {
- return nil, errcode.ErrInternal.Wrap(err)
- }
-
- if contact.IsSamePK(accSK.GetPublic()) {
+ accountPublicKey := m.memberDevice.Member()
+ if contact.IsSamePK(accountPublicKey) {
return nil, errcode.ErrContactRequestSameAccount
}
@@ -656,12 +640,8 @@ func (m *MetadataStore) ContactRequestIncomingReceived(ctx context.Context, cont
return nil, errcode.ErrInvalidInput.Wrap(err)
}
- accSK, err := m.devKS.AccountPrivKey()
- if err != nil {
- return nil, errcode.ErrInternal.Wrap(err)
- }
-
- if contact.IsSamePK(accSK.GetPublic()) {
+ accountPublicKey := m.memberDevice.Member()
+ if contact.IsSamePK(accountPublicKey) {
return nil, errcode.ErrContactRequestSameAccount
}
@@ -730,12 +710,8 @@ func (m *MetadataStore) ContactBlock(ctx context.Context, pk crypto.PubKey) (ope
return nil, errcode.ErrGroupInvalidType
}
- accSK, err := m.devKS.AccountPrivKey()
- if err != nil {
- return nil, errcode.ErrInternal.Wrap(err)
- }
-
- if accSK.GetPublic().Equals(pk) {
+ accountPublicKey := m.memberDevice.Member()
+ if accountPublicKey.Equals(pk) {
return nil, errcode.ErrInvalidInput
}
@@ -764,12 +740,12 @@ func (m *MetadataStore) ContactSendAliasKey(ctx context.Context) (operation.Oper
return nil, errcode.ErrGroupInvalidType
}
- sk, err := m.devKS.AccountProofPrivKey()
+ accountProofPublicKey, err := m.secretStore.GetAccountProofPublicKey()
if err != nil {
return nil, errcode.ErrInternal.Wrap(err)
}
- alias, err := sk.GetPublic().Raw()
+ alias, err := accountProofPublicKey.Raw()
if err != nil {
return nil, errcode.ErrInternal.Wrap(err)
}
@@ -869,30 +845,16 @@ type accountGroupEvent interface {
}
func (m *MetadataStore) attributeSignAndAddEvent(ctx context.Context, evt accountSignableEvent, eventType protocoltypes.EventType) (operation.Operation, error) {
- md, err := m.devKS.MemberDeviceForGroup(m.g)
- if err != nil {
- return nil, errcode.ErrInternal.Wrap(err)
- }
+ evt.SetDevicePK(m.devicePublicKeyRaw)
- m.logger.Debug("Got member device", tyber.FormatStepLogFields(ctx, []tyber.Detail{{Name: "MemberDevice", Description: fmt.Sprint(md)}})...)
-
- device, err := md.PrivateDevice().GetPublic().Raw()
- if err != nil {
- return nil, errcode.ErrSerialization.Wrap(err)
- }
-
- m.logger.Debug("Got member device public key", tyber.FormatStepLogFields(ctx, []tyber.Detail{{Name: "MemberDevicePublicKey", Description: base64.RawURLEncoding.EncodeToString(device)}})...)
-
- evt.SetDevicePK(device)
-
- sig, err := signProto(evt, md.PrivateDevice())
+ sig, err := signProtoWithDevice(evt, m.memberDevice)
if err != nil {
return nil, errcode.ErrCryptoSignature.Wrap(err)
}
m.logger.Debug("Signed event", tyber.FormatStepLogFields(ctx, []tyber.Detail{{Name: "Signature", Description: base64.RawURLEncoding.EncodeToString(sig)}})...)
- return metadataStoreAddEvent(ctx, m, m.g, eventType, evt, sig)
+ return metadataStoreAddEvent(ctx, m, m.group, eventType, evt, sig)
}
func (m *MetadataStore) contactAction(ctx context.Context, pk crypto.PubKey, event accountContactEvent, evtType protocoltypes.EventType) (operation.Operation, error) {
@@ -994,37 +956,40 @@ func constructorFactoryGroupMetadata(s *WeshOrbitDB, logger *zap.Logger) iface.S
shortGroupType := strings.TrimPrefix(g.GetGroupType().String(), "GroupType")
b64GroupPK := base64.RawURLEncoding.EncodeToString(g.PublicKey)
- var (
- md *cryptoutil.OwnMemberDevice
- replication = false
- )
+ replication := false
if options.EventBus == nil {
options.EventBus = eventbus.NewBus()
}
- if s.deviceKeystore == nil {
+ store := &MetadataStore{
+ eventBus: options.EventBus,
+ group: g,
+ logger: logger,
+ secretStore: s.secretStore,
+ }
+
+ if s.replicationMode {
replication = true
} else {
- md, err = s.deviceKeystore.MemberDeviceForGroup(g)
- if errcode.Is(err, errcode.ErrInvalidInput) {
- replication = true
- } else if err != nil {
- return nil, errcode.TODO.Wrap(err)
+ var err error
+
+ store.memberDevice, err = s.secretStore.GetOwnMemberDeviceForGroup(g)
+ if err != nil {
+ if errcode.Is(err, errcode.ErrInvalidInput) {
+ replication = true
+ } else {
+ return nil, errcode.ErrOrbitDBInit.Wrap(err)
+ }
+ } else {
+ store.devicePublicKeyRaw, err = store.memberDevice.Device().Raw()
+ if err != nil {
+ return nil, errcode.ErrOrbitDBInit.Wrap(err)
+ }
}
}
- ctx, cancel := context.WithCancel(context.Background())
-
- store := &MetadataStore{
- ctx: ctx,
- cancel: cancel,
- eventBus: options.EventBus,
- g: g,
- mks: s.messageKeystore,
- devKS: s.deviceKeystore,
- logger: logger,
- }
+ store.ctx, store.cancel = context.WithCancel(context.Background())
if err := store.initEmitter(); err != nil {
return nil, fmt.Errorf("unable to init emitters: %w", err)
@@ -1033,7 +998,7 @@ func constructorFactoryGroupMetadata(s *WeshOrbitDB, logger *zap.Logger) iface.S
if replication {
options.Index = basestore.NewNoopIndex
if err := store.InitBaseStore(ipfs, identity, addr, options); err != nil {
- cancel()
+ store.cancel()
return nil, errcode.ErrOrbitDBInit.Wrap(err)
}
@@ -1045,7 +1010,7 @@ func constructorFactoryGroupMetadata(s *WeshOrbitDB, logger *zap.Logger) iface.S
new(stores.EventReplicated),
}, eventbus.BufSize(128))
if err != nil {
- cancel()
+ store.cancel()
return nil, fmt.Errorf("unable to subscribe to store events")
}
@@ -1105,11 +1070,11 @@ func constructorFactoryGroupMetadata(s *WeshOrbitDB, logger *zap.Logger) iface.S
}
}
}
- }(ctx)
+ }(store.ctx)
- options.Index = newMetadataIndex(ctx, g, md.Public(), s.deviceKeystore)
+ options.Index = newMetadataIndex(store.ctx, g, store.memberDevice, s.secretStore)
if err := store.InitBaseStore(ipfs, identity, addr, options); err != nil {
- cancel()
+ store.cancel()
return nil, errcode.ErrOrbitDBInit.Wrap(err)
}
@@ -1117,23 +1082,6 @@ func constructorFactoryGroupMetadata(s *WeshOrbitDB, logger *zap.Logger) iface.S
}
}
-func newSecretEntryPayload(localDevicePrivKey crypto.PrivKey, remoteMemberPubKey crypto.PubKey, secret *protocoltypes.DeviceSecret, group *protocoltypes.Group) ([]byte, error) {
- message, err := secret.Marshal()
- if err != nil {
- return nil, errcode.ErrSerialization.Wrap(err)
- }
-
- mongPriv, mongPub, err := cryptoutil.EdwardsToMontgomery(localDevicePrivKey, remoteMemberPubKey)
- if err != nil {
- return nil, errcode.ErrCryptoKeyConversion.Wrap(err)
- }
-
- nonce := groupIDToNonce(group)
- encryptedSecret := box.Seal(nil, message, nonce, mongPub, mongPriv)
-
- return encryptedSecret, nil
-}
-
func (m *MetadataStore) SendPushToken(ctx context.Context, t *protocoltypes.PushMemberTokenUpdate) (operation.Operation, error) {
m.logger.Debug("sending push token to device", logutil.PrivateString("server", t.Server.ServiceAddr))
return m.attributeSignAndAddEvent(ctx, &protocoltypes.PushMemberTokenUpdate{
@@ -1190,28 +1138,6 @@ func (m *MetadataStore) GetPushTokenForDevice(d crypto.PubKey) (*protocoltypes.P
return token, nil
}
-func (m *MetadataStore) MemberPK() (crypto.PubKey, error) {
- memDev, err := m.devKS.MemberDeviceForGroup(m.g)
- if err != nil {
- return nil, errcode.ErrInternal.Wrap(err)
- }
-
- return memDev.PrivateMember().GetPublic(), nil
-}
-
-func (m *MetadataStore) DevicePK() (crypto.PubKey, error) {
- memDev, err := m.devKS.MemberDeviceForGroup(m.g)
- if err != nil {
- return nil, errcode.ErrInternal.Wrap(err)
- }
-
- return memDev.PrivateDevice().GetPublic(), nil
-}
-
-func (m *MetadataStore) Group() *protocoltypes.Group {
- return m.g.Copy()
-}
-
func (m *MetadataStore) initEmitter() (err error) {
if m.emitters.metadataReceived, err = m.eventBus.Emitter(new(EventMetadataReceived)); err != nil {
return
diff --git a/store_metadata_index.go b/store_metadata_index.go
index 60cab359..e6d887c5 100644
--- a/store_metadata_index.go
+++ b/store_metadata_index.go
@@ -15,12 +15,13 @@ import (
"berty.tech/weshnet/pkg/cryptoutil"
"berty.tech/weshnet/pkg/errcode"
"berty.tech/weshnet/pkg/protocoltypes"
+ "berty.tech/weshnet/pkg/secretstore"
)
// FIXME: replace members, devices, sentSecrets, contacts and groups by a circular buffer to avoid an attack by RAM saturation
type metadataStoreIndex struct {
- members map[string][]*cryptoutil.MemberDevice
- devices map[string]*cryptoutil.MemberDevice
+ members map[string][]secretstore.MemberDevice
+ devices map[string]secretstore.MemberDevice
handledEvents map[string]struct{}
sentSecrets map[string]struct{}
admins map[crypto.PubKey]struct{}
@@ -40,9 +41,9 @@ type metadataStoreIndex struct {
eventsContactAddAliasKey []*protocoltypes.ContactAddAliasKey
ownAliasKeySent bool
otherAliasKey []byte
- g *protocoltypes.Group
- ownMemberDevice *cryptoutil.MemberDevice
- deviceKeystore cryptoutil.DeviceKeystore
+ group *protocoltypes.Group
+ ownMemberDevice secretstore.MemberDevice
+ secretStore secretstore.SecretStore
ctx context.Context
lock sync.RWMutex
logger *zap.Logger
@@ -86,11 +87,11 @@ func (m *metadataStoreIndex) UpdateIndex(log ipfslog.Log, _ []ipfslog.Entry) err
_, alreadyHandledEvent := m.handledEvents[e.GetHash().String()]
// TODO: improve account events handling
- if m.g.GroupType != protocoltypes.GroupTypeAccount && alreadyHandledEvent {
+ if m.group.GroupType != protocoltypes.GroupTypeAccount && alreadyHandledEvent {
continue
}
- metaEvent, event, err := openMetadataEntry(log, e, m.g)
+ metaEvent, event, err := openMetadataEntry(log, e, m.group)
if err != nil {
m.logger.Error("unable to open metadata entry", zap.Error(err))
continue
@@ -150,21 +151,16 @@ func (m *metadataStoreIndex) handleGroupAddMemberDevice(event proto.Message) err
return nil
}
- m.devices[string(e.DevicePK)] = &cryptoutil.MemberDevice{
- Member: member,
- Device: device,
- }
+ memberDevice := secretstore.NewMemberDevice(member, device)
- m.members[string(e.MemberPK)] = append(m.members[string(e.MemberPK)], &cryptoutil.MemberDevice{
- Member: member,
- Device: device,
- })
+ m.devices[string(e.DevicePK)] = memberDevice
+ m.members[string(e.MemberPK)] = append(m.members[string(e.MemberPK)], memberDevice)
return nil
}
-func (m *metadataStoreIndex) handleGroupAddDeviceSecret(event proto.Message) error {
- e, ok := event.(*protocoltypes.GroupAddDeviceSecret)
+func (m *metadataStoreIndex) handleGroupAddDeviceChainKey(event proto.Message) error {
+ e, ok := event.(*protocoltypes.GroupAddDeviceChainKey)
if !ok {
return errcode.ErrInvalidInput
}
@@ -179,32 +175,36 @@ func (m *metadataStoreIndex) handleGroupAddDeviceSecret(event proto.Message) err
return errcode.ErrDeserialization.Wrap(err)
}
- if m.ownMemberDevice.Device.Equals(senderPK) {
+ if m.ownMemberDevice.Device().Equals(senderPK) {
m.sentSecrets[string(e.DestMemberPK)] = struct{}{}
}
return nil
}
-func (m *metadataStoreIndex) getMemberByDevice(pk crypto.PubKey) (crypto.PubKey, error) {
+func (m *metadataStoreIndex) getMemberByDevice(devicePublicKey crypto.PubKey) (crypto.PubKey, error) {
m.lock.RLock()
defer m.lock.RUnlock()
- return m.unsafeGetMemberByDevice(pk)
-}
-
-func (m *metadataStoreIndex) unsafeGetMemberByDevice(pk crypto.PubKey) (crypto.PubKey, error) {
- id, err := pk.Raw()
+ publicKeyBytes, err := devicePublicKey.Raw()
if err != nil {
return nil, errcode.ErrInvalidInput.Wrap(err)
}
- device, ok := m.devices[string(id)]
+ return m.unsafeGetMemberByDevice(publicKeyBytes)
+}
+
+func (m *metadataStoreIndex) unsafeGetMemberByDevice(publicKeyBytes []byte) (crypto.PubKey, error) {
+ if l := len(publicKeyBytes); l != cryptoutil.KeySize {
+ return nil, errcode.ErrInvalidInput.Wrap(fmt.Errorf("invalid private key size, expected %d got %d", cryptoutil.KeySize, l))
+ }
+
+ device, ok := m.devices[string(publicKeyBytes)]
if !ok {
return nil, errcode.ErrMissingInput
}
- return device.Member, nil
+ return device.Member(), nil
}
func (m *metadataStoreIndex) getDevicesForMember(pk crypto.PubKey) ([]crypto.PubKey, error) {
@@ -223,7 +223,7 @@ func (m *metadataStoreIndex) getDevicesForMember(pk crypto.PubKey) ([]crypto.Pub
ret := make([]crypto.PubKey, len(mds))
for i, md := range mds {
- ret[i] = md.Device
+ ret[i] = md.Device()
}
return ret, nil
@@ -278,7 +278,7 @@ func (m *metadataStoreIndex) listMembers() []crypto.PubKey {
i := 0
for _, md := range m.members {
- members[i] = md[0].Member
+ members[i] = md[0].Member()
i++
}
@@ -293,7 +293,7 @@ func (m *metadataStoreIndex) listDevices() []crypto.PubKey {
i := 0
for _, md := range m.devices {
- devices[i] = md.Device
+ devices[i] = md.Device()
i++
}
@@ -415,7 +415,7 @@ func (m *metadataStoreIndex) handleContactRequestReferenceReset(event proto.Mess
}
func (m *metadataStoreIndex) registerContactFromGroupPK(ac *AccountContact) error {
- if m.g.GroupType != protocoltypes.GroupTypeAccount {
+ if m.group.GroupType != protocoltypes.GroupTypeAccount {
return errcode.ErrGroupInvalidType
}
@@ -424,17 +424,12 @@ func (m *metadataStoreIndex) registerContactFromGroupPK(ac *AccountContact) erro
return errcode.ErrDeserialization.Wrap(err)
}
- sk, err := m.deviceKeystore.ContactGroupPrivKey(contactPK)
- if err != nil {
- return err
- }
-
- g, err := cryptoutil.GetGroupForContact(sk)
+ group, err := m.secretStore.GetGroupForContact(contactPK)
if err != nil {
return errcode.ErrOrbitDBOpen.Wrap(err)
}
- m.contactsFromGroupPK[string(g.PublicKey)] = ac
+ m.contactsFromGroupPK[string(group.PublicKey)] = ac
return nil
}
@@ -725,7 +720,7 @@ func (m *metadataStoreIndex) handlePushDeviceTokenRegistered(event proto.Message
return errcode.ErrInvalidInput
}
- devicePK, err := m.ownMemberDevice.Device.Raw()
+ devicePK, err := m.ownMemberDevice.Device().Raw()
if err != nil {
return errcode.ErrSerialization.Wrap(err)
}
@@ -753,7 +748,7 @@ func (m *metadataStoreIndex) handlePushServerTokenRegistered(event proto.Message
return errcode.ErrInvalidInput
}
- devicePK, err := m.ownMemberDevice.Device.Raw()
+ devicePK, err := m.ownMemberDevice.Device().Raw()
if err != nil {
return errcode.ErrSerialization.Wrap(err)
}
@@ -801,11 +796,11 @@ func (m *metadataStoreIndex) listOtherMembersDevices() []crypto.PubKey {
m.lock.RLock()
defer m.lock.RUnlock()
- if m.ownMemberDevice == nil || m.ownMemberDevice.Member == nil {
+ if m.ownMemberDevice == nil || m.ownMemberDevice.Member() == nil {
return nil
}
- ownMemberPK, err := m.ownMemberDevice.Member.Raw()
+ ownMemberPK, err := m.ownMemberDevice.Member().Raw()
if err != nil {
m.logger.Warn("unable to serialize member pubkey", zap.Error(err))
return nil
@@ -818,7 +813,7 @@ func (m *metadataStoreIndex) listOtherMembersDevices() []crypto.PubKey {
}
for _, md := range devicesForMember {
- devices = append(devices, md.Device)
+ devices = append(devices, md.Device())
}
}
@@ -872,23 +867,18 @@ func (m *metadataStoreIndex) getCurrentDevicePushServer() *protocoltypes.PushDev
func (m *metadataStoreIndex) postHandlerSentAliases() error {
for _, evt := range m.eventsContactAddAliasKey {
- pk, err := crypto.UnmarshalEd25519PublicKey(evt.DevicePK)
- if err != nil {
- return errcode.ErrDeserialization.Wrap(err)
- }
-
- memberPK, err := m.unsafeGetMemberByDevice(pk)
+ memberPublicKey, err := m.unsafeGetMemberByDevice(evt.DevicePK)
if err != nil {
return fmt.Errorf("couldn't get member for device")
}
- if memberPK.Equals(m.ownMemberDevice.Member) {
+ if memberPublicKey.Equals(m.ownMemberDevice.Member()) {
m.ownAliasKeySent = true
continue
}
- if _, err = crypto.UnmarshalEd25519PublicKey(evt.AliasPK); err != nil {
- return errcode.ErrDeserialization.Wrap(err)
+ if l := len(evt.AliasPK); l != cryptoutil.KeySize {
+ return errcode.ErrInvalidInput.Wrap(fmt.Errorf("invalid alias key size, expected %d, got %d", cryptoutil.KeySize, l))
}
m.otherAliasKey = evt.AliasPK
@@ -901,11 +891,11 @@ func (m *metadataStoreIndex) postHandlerSentAliases() error {
// nolint:staticcheck
// newMetadataIndex returns a new index to manage the list of the group members
-func newMetadataIndex(ctx context.Context, g *protocoltypes.Group, md *cryptoutil.MemberDevice, devKS cryptoutil.DeviceKeystore) iface.IndexConstructor {
+func newMetadataIndex(ctx context.Context, g *protocoltypes.Group, md secretstore.MemberDevice, secretStore secretstore.SecretStore) iface.IndexConstructor {
return func(publicKey []byte) iface.StoreIndex {
m := &metadataStoreIndex{
- members: map[string][]*cryptoutil.MemberDevice{},
- devices: map[string]*cryptoutil.MemberDevice{},
+ members: map[string][]secretstore.MemberDevice{},
+ devices: map[string]secretstore.MemberDevice{},
admins: map[crypto.PubKey]struct{}{},
sentSecrets: map[string]struct{}{},
handledEvents: map[string]struct{}{},
@@ -915,9 +905,9 @@ func newMetadataIndex(ctx context.Context, g *protocoltypes.Group, md *cryptouti
serviceTokens: map[string]*protocoltypes.ServiceToken{},
contactRequestMetadata: map[string][]byte{},
membersPushTokens: map[string]*protocoltypes.PushMemberTokenUpdate{},
- g: g,
+ group: g,
ownMemberDevice: md,
- deviceKeystore: devKS,
+ secretStore: secretStore,
ctx: ctx,
logger: zap.NewNop(),
}
@@ -936,7 +926,7 @@ func newMetadataIndex(ctx context.Context, g *protocoltypes.Group, md *cryptouti
protocoltypes.EventTypeAccountGroupJoined: {m.handleGroupJoined},
protocoltypes.EventTypeAccountGroupLeft: {m.handleGroupLeft},
protocoltypes.EventTypeContactAliasKeyAdded: {m.handleContactAliasKeyAdded},
- protocoltypes.EventTypeGroupDeviceSecretAdded: {m.handleGroupAddDeviceSecret},
+ protocoltypes.EventTypeGroupDeviceChainKeyAdded: {m.handleGroupAddDeviceChainKey},
protocoltypes.EventTypeGroupMemberDeviceAdded: {m.handleGroupAddMemberDevice},
protocoltypes.EventTypeMultiMemberGroupAdminRoleGranted: {m.handleMultiMemberGrantAdminRole},
protocoltypes.EventTypeMultiMemberGroupInitialMemberAnnounced: {m.handleMultiMemberInitialMember},
diff --git a/store_metadata_test.go b/store_metadata_test.go
index 82394813..55eaa673 100644
--- a/store_metadata_test.go
+++ b/store_metadata_test.go
@@ -17,7 +17,6 @@ import (
"github.com/stretchr/testify/require"
"go.uber.org/zap"
- "berty.tech/weshnet/pkg/cryptoutil"
"berty.tech/weshnet/pkg/ipfsutil"
"berty.tech/weshnet/pkg/protocoltypes"
"berty.tech/weshnet/pkg/testutil"
@@ -43,8 +42,8 @@ func TestMetadataStoreSecret_Basic(t *testing.T) {
go peers[0].GC.WatchNewMembersAndSendSecrets()
go peers[1].GC.WatchNewMembersAndSendSecrets()
- go waitForBertyEventType(ctx, t, msA, protocoltypes.EventTypeGroupDeviceSecretAdded, 2, secretsAdded)
- go waitForBertyEventType(ctx, t, msB, protocoltypes.EventTypeGroupDeviceSecretAdded, 2, secretsAdded)
+ go waitForBertyEventType(ctx, t, msA, protocoltypes.EventTypeGroupDeviceChainKeyAdded, 2, secretsAdded)
+ go waitForBertyEventType(ctx, t, msB, protocoltypes.EventTypeGroupDeviceChainKeyAdded, 2, secretsAdded)
inviteAllPeersToGroup(ctx, t, peers, groupSK)
devPkA := peers[0].GC.DevicePubKey()
@@ -55,24 +54,6 @@ func TestMetadataStoreSecret_Basic(t *testing.T) {
_ = devPkA
_ = devPkB
-
- // secretAForB, err := msB.DeviceSecret(devPkA)
- // assert.NoError(t, err)
- //
- // secretBForA, err := msA.DeviceSecret(devPkB)
- // assert.NoError(t, err)
- //
- // secretAForA, err := peers[0].GetGroupContext().DeviceSecret(ctx)
- // assert.NoError(t, err)
- //
- // secretBForB, err := peers[1].GetGroupContext().DeviceSecret(ctx)
- // assert.NoError(t, err)
- //
- // assert.Equal(t, secretAForA.ChainKey, secretAForB.ChainKey)
- // assert.Equal(t, secretAForA.Counter, secretAForB.Counter)
- //
- // assert.Equal(t, secretBForB.ChainKey, secretBForA.ChainKey)
- // assert.Equal(t, secretBForB.Counter, secretBForA.Counter)
}
func TestMetadataStoreMember(t *testing.T) {
@@ -193,9 +174,9 @@ func TestMetadataRendezvousPointLifecycle(t *testing.T) {
meta := ownCG.MetadataStore()
- accSK, err := peers[0].DevKS.AccountPrivKey()
+ _, accountMemberDevice, err := peers[0].SecretStore.GetGroupForAccount()
assert.NoError(t, err)
- accPK, err := accSK.GetPublic().Raw()
+ accPK, err := accountMemberDevice.Member().Raw()
assert.NoError(t, err)
enabled, shareableContact := meta.GetIncomingContactRequestsStatus()
@@ -521,10 +502,7 @@ func TestMetadataAliasLifecycle(t *testing.T) {
_, err := peers[0].GC.MetadataStore().ContactSendAliasKey(ctx)
require.Error(t, err)
- sk, err := peers[0].DevKS.ContactGroupPrivKey(peers[1].GC.MemberPubKey())
- require.NoError(t, err)
-
- g, err := cryptoutil.GetGroupForContact(sk)
+ g, err := peers[0].SecretStore.GetGroupForContact(peers[1].GC.MemberPubKey())
require.NoError(t, err)
cg0, err := peers[0].DB.OpenGroup(ctx, g, nil)
@@ -542,10 +520,7 @@ func TestMetadataAliasLifecycle(t *testing.T) {
require.Empty(t, cg0.MetadataStore().Index().(*metadataStoreIndex).otherAliasKey)
require.True(t, cg0.MetadataStore().Index().(*metadataStoreIndex).ownAliasKeySent)
- sk, err = peers[1].DevKS.ContactGroupPrivKey(peers[0].GC.MemberPubKey())
- require.NoError(t, err)
-
- g, err = cryptoutil.GetGroupForContact(sk)
+ g, err = peers[1].SecretStore.GetGroupForContact(peers[0].GC.MemberPubKey())
require.NoError(t, err)
cg1, err := peers[1].DB.OpenGroup(ctx, g, nil)
diff --git a/testing.go b/testing.go
index 97295262..157c655d 100644
--- a/testing.go
+++ b/testing.go
@@ -3,7 +3,6 @@ package weshnet
import (
"bytes"
"context"
- crand "crypto/rand"
"fmt"
"io"
"os"
@@ -18,7 +17,6 @@ import (
grpc_ctxtags "github.com/grpc-ecosystem/go-grpc-middleware/tags"
datastore "github.com/ipfs/go-datastore"
ds_sync "github.com/ipfs/go-datastore/sync"
- keystore "github.com/ipfs/go-ipfs-keystore"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/peer"
libp2p_mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
@@ -31,10 +29,10 @@ import (
orbitdb "berty.tech/go-orbit-db"
"berty.tech/go-orbit-db/pubsub/pubsubraw"
"berty.tech/weshnet/internal/datastoreutil"
- "berty.tech/weshnet/pkg/cryptoutil"
"berty.tech/weshnet/pkg/errcode"
"berty.tech/weshnet/pkg/ipfsutil"
"berty.tech/weshnet/pkg/protocoltypes"
+ "berty.tech/weshnet/pkg/secretstore"
"berty.tech/weshnet/pkg/testutil"
"berty.tech/weshnet/pkg/tinder"
)
@@ -52,10 +50,17 @@ func NewTestOrbitDB(ctx context.Context, t *testing.T, logger *zap.Logger, node
baseDS = datastoreutil.NewNamespacedDatastore(baseDS, datastore.NewKey(selfKey.ID().String()))
+ secretStore, err := secretstore.NewSecretStore(baseDS, nil)
+ require.NoError(t, err)
+ t.Cleanup(func() {
+ _ = secretStore.Close()
+ })
+
pubSub := pubsubraw.NewPubSub(node.PubSub(), selfKey.ID(), logger, nil)
odb, err := NewWeshOrbitDB(ctx, api, &NewOrbitDBOptions{
- Datastore: baseDS,
+ Datastore: baseDS,
+ SecretStore: secretStore,
NewOrbitDBOptions: orbitdb.NewOrbitDBOptions{
Logger: logger,
PubSub: pubSub,
@@ -67,11 +72,10 @@ func NewTestOrbitDB(ctx context.Context, t *testing.T, logger *zap.Logger, node
}
type mockedPeer struct {
- CoreAPI ipfsutil.CoreAPIMock
- DB *WeshOrbitDB
- GC *GroupContext
- MKS *cryptoutil.MessageKeystore
- DevKS cryptoutil.DeviceKeystore
+ CoreAPI ipfsutil.CoreAPIMock
+ DB *WeshOrbitDB
+ GC *GroupContext
+ SecretStore secretstore.SecretStore
}
func (m *mockedPeer) PeerInfo() peer.AddrInfo {
@@ -84,18 +88,17 @@ type TestingProtocol struct {
Service Service
Client ServiceClient
- RootDatastore datastore.Batching
- DeviceKeystore cryptoutil.DeviceKeystore
- IpfsCoreAPI ipfsutil.ExtendedCoreAPI
- OrbitDB *WeshOrbitDB
- GroupDatastore *cryptoutil.GroupDatastore
+ RootDatastore datastore.Batching
+ IpfsCoreAPI ipfsutil.ExtendedCoreAPI
+ OrbitDB *WeshOrbitDB
+ SecretStore secretstore.SecretStore
}
type TestingOpts struct {
Logger *zap.Logger
Mocknet libp2p_mocknet.Mocknet
DiscoveryServer *tinder.MockDriverServer
- DeviceKeystore cryptoutil.DeviceKeystore
+ SecretStore secretstore.SecretStore
CoreAPIMock ipfsutil.CoreAPIMock
OrbitDB *WeshOrbitDB
ConnectFunc ConnectTestingProtocolFunc
@@ -124,11 +127,13 @@ func NewTestingProtocol(ctx context.Context, t testing.TB, opts *TestingOpts, ds
node = ipfsutil.TestingCoreAPIUsingMockNet(ctx, t, ipfsopts)
}
- deviceKeystore := opts.DeviceKeystore
- if deviceKeystore == nil {
- deviceKeystore = cryptoutil.NewDeviceKeystore(
- ipfsutil.NewDatastoreKeystore(datastoreutil.NewNamespacedDatastore(ds, datastore.NewKey(NamespaceDeviceKeystore))),
- nil)
+ secretStore := opts.SecretStore
+ if secretStore == nil {
+ var err error
+ secretStore, err = secretstore.NewInMemSecretStore(&secretstore.NewSecretStoreOptions{
+ OutOfStorePrivateKey: opts.PushSK,
+ })
+ require.NoError(t, err)
}
odb := opts.OrbitDB
@@ -142,26 +147,22 @@ func NewTestingProtocol(ctx context.Context, t testing.TB, opts *TestingOpts, ds
PubSub: pubSub,
Logger: opts.Logger,
},
- Datastore: ds,
- DeviceKeystore: deviceKeystore,
+ Datastore: ds,
+ SecretStore: secretStore,
})
require.NoError(t, err)
}
- groupDatastore, err := cryptoutil.NewGroupDatastore(ds)
- require.NoError(t, err)
-
serviceOpts := Opts{
- Host: node.MockNode().PeerHost,
- PubSub: node.PubSub(),
- Logger: opts.Logger,
- RootDatastore: ds,
- DeviceKeystore: deviceKeystore,
- IpfsCoreAPI: node.API(),
- OrbitDB: odb,
- TinderService: node.Tinder(),
- PushKey: opts.PushSK,
- GroupDatastore: groupDatastore,
+ Host: node.MockNode().PeerHost,
+ PubSub: node.PubSub(),
+ Logger: opts.Logger,
+ RootDatastore: ds,
+ IpfsCoreAPI: node.API(),
+ OrbitDB: odb,
+ TinderService: node.Tinder(),
+ OutOfStorePrivateKey: opts.PushSK,
+ SecretStore: secretStore,
}
service, cleanupService := TestingService(ctx, t, serviceOpts)
@@ -194,11 +195,10 @@ func NewTestingProtocol(ctx context.Context, t testing.TB, opts *TestingOpts, ds
Client: client,
Service: service,
- RootDatastore: ds,
- DeviceKeystore: deviceKeystore,
- IpfsCoreAPI: node.API(),
- OrbitDB: odb,
- GroupDatastore: serviceOpts.GroupDatastore,
+ RootDatastore: ds,
+ IpfsCoreAPI: node.API(),
+ OrbitDB: odb,
+ SecretStore: secretStore,
}
cleanup := func() {
server.Stop()
@@ -352,11 +352,11 @@ func CreatePeersWithGroupTest(ctx context.Context, t testing.TB, pathBase string
logger, cleanupLogger := testutil.Logger(t)
- var devKS cryptoutil.DeviceKeystore
+ var secretStore secretstore.SecretStore
mockedPeers := make([]*mockedPeer, memberCount*deviceCount)
- g, groupSK, err := NewGroupMultiMember()
+ group, groupPrivateKey, err := NewGroupMultiMember()
if err != nil {
t.Fatal(err)
}
@@ -377,42 +377,37 @@ func CreatePeersWithGroupTest(ctx context.Context, t testing.TB, pathBase string
ca := ipfsutil.TestingCoreAPIUsingMockNet(ctx, t, &ipfsopts)
if j == 0 {
- devKS = cryptoutil.NewDeviceKeystore(keystore.NewMemKeystore(), nil)
+ secretStore, err = secretstore.NewInMemSecretStore(nil)
+ require.NoError(t, err)
} else {
- accSK, err := devKS.AccountPrivKey()
- require.NoError(t, err, "deviceKeystore private key")
-
- accProofSK, err := devKS.AccountProofPrivKey()
- require.NoError(t, err, "deviceKeystore private proof key")
+ privateKeyBytes, proofPrivateKeyBytes, err := secretStore.ExportAccountKeysForBackup()
+ require.NoError(t, err, "ExportAccountKeysForBackup error")
- devKS, err = cryptoutil.NewWithExistingKeys(keystore.NewMemKeystore(), accSK, accProofSK)
- require.NoError(t, err, "deviceKeystore from existing keys")
+ secretStore, err = secretstore.NewInMemSecretStore(nil)
+ require.NoError(t, err)
+ require.NoError(t, secretStore.ImportAccountKeys(privateKeyBytes, proofPrivateKeyBytes))
}
- mk, cleanupMessageKeystore := cryptoutil.NewInMemMessageKeystore(logger)
-
db, err := NewWeshOrbitDB(ctx, ca.API(), &NewOrbitDBOptions{
NewOrbitDBOptions: orbitdb.NewOrbitDBOptions{
Logger: logger,
},
- DeviceKeystore: devKS,
- MessageKeystore: mk,
+ SecretStore: secretStore,
})
if err != nil {
t.Fatal(err)
}
- gc, err := db.OpenGroup(ctx, g, nil)
+ gc, err := db.OpenGroup(ctx, group, nil)
if err != nil {
t.Fatalf("err: creating new group context, %v", err)
}
mp := &mockedPeer{
- CoreAPI: ca,
- DB: db,
- GC: gc,
- MKS: mk,
- DevKS: devKS,
+ CoreAPI: ca,
+ DB: db,
+ GC: gc,
+ SecretStore: secretStore,
}
// setup cleanup
@@ -431,7 +426,7 @@ func CreatePeersWithGroupTest(ctx context.Context, t testing.TB, pathBase string
assert.NoError(t, err)
}
- cleanupMessageKeystore()
+ _ = secretStore.Close()
}
mockedPeers[deviceIndex] = mp
@@ -441,7 +436,7 @@ func CreatePeersWithGroupTest(ctx context.Context, t testing.TB, pathBase string
connectPeers(ctx, t, ipfsopts.Mocknet)
- return mockedPeers, groupSK, func() {
+ return mockedPeers, groupPrivateKey, func() {
for _, cleanup := range cls {
cleanup()
}
@@ -489,34 +484,6 @@ type ServiceMethods interface {
GetCurrentDevicePushConfig() (*protocoltypes.PushServiceReceiver, *protocoltypes.PushServer)
}
-func CreateVirtualOtherPeerSecretsShareSecret(t testing.TB, ctx context.Context, membersStores []*MetadataStore) (*cryptoutil.OwnMemberDevice, *protocoltypes.DeviceSecret) {
- // Manually adding another member to the group
- otherMemberSK, _, err := crypto.GenerateEd25519Key(crand.Reader)
- require.NoError(t, err)
-
- otherDeviceSK, _, err := crypto.GenerateEd25519Key(crand.Reader)
- require.NoError(t, err)
-
- otherMD := cryptoutil.NewOwnMemberDevice(otherMemberSK, otherDeviceSK)
- ds, err := cryptoutil.NewDeviceSecret()
- require.NoError(t, err)
-
- for _, store := range membersStores {
- _, err = MetadataStoreAddDeviceToGroup(ctx, store, store.Group(), otherMD)
- require.NoError(t, err)
-
- memPK, err := store.MemberPK()
- require.NoError(t, err)
-
- _, err = MetadataStoreSendSecret(ctx, store, store.Group(), otherMD, memPK, ds)
- require.NoError(t, err)
- }
-
- time.Sleep(time.Millisecond * 200)
-
- return otherMD, ds
-}
-
func GetRootDatastoreForPath(dir string, key []byte, salt []byte, logger *zap.Logger) (datastore.Batching, error) {
inMemory := dir == InMemoryDir
@@ -705,12 +672,12 @@ func CreateMultiMemberGroupInstance(ctx context.Context, t *testing.T, tps ...*T
}
func isEventAddSecretTargetedToMember(ownRawPK []byte, evt *protocoltypes.GroupMetadataEvent) ([]byte, error) {
- // Only count EventTypeGroupDeviceSecretAdded events
- if evt.Metadata.EventType != protocoltypes.EventTypeGroupDeviceSecretAdded {
+ // Only count EventTypeGroupDeviceChainKeyAdded events
+ if evt.Metadata.EventType != protocoltypes.EventTypeGroupDeviceChainKeyAdded {
return nil, nil
}
- sec := &protocoltypes.GroupAddDeviceSecret{}
+ sec := &protocoltypes.GroupAddDeviceChainKey{}
err := sec.Unmarshal(evt.Event)
if err != nil {
return nil, err