diff --git a/common/pkg/acl/aclrecordproto/aclrecord.pb.go b/common/pkg/acl/aclrecordproto/aclrecord.pb.go index 385d7df5..bca4e5d8 100644 --- a/common/pkg/acl/aclrecordproto/aclrecord.pb.go +++ b/common/pkg/acl/aclrecordproto/aclrecord.pb.go @@ -825,7 +825,7 @@ func (m *ACLUserJoin) GetEncryptedReadKeys() [][]byte { type ACLUserRemove struct { Identity []byte `protobuf:"bytes,1,opt,name=identity,proto3" json:"identity,omitempty"` - ReadKeyReplaces []*ACLReadKeyReplace `protobuf:"bytes,3,rep,name=readKeyReplaces,proto3" json:"readKeyReplaces,omitempty"` + ReadKeyReplaces []*ACLReadKeyReplace `protobuf:"bytes,2,rep,name=readKeyReplaces,proto3" json:"readKeyReplaces,omitempty"` } func (m *ACLUserRemove) Reset() { *m = ACLUserRemove{} } @@ -1058,14 +1058,14 @@ var fileDescriptor_14abe0d1b4206d54 = []byte{ 0xc2, 0xb5, 0xdc, 0xc3, 0xc9, 0x64, 0xc2, 0x5c, 0x65, 0x2f, 0x66, 0xa3, 0x28, 0x4c, 0xe6, 0xc6, 0x0e, 0x74, 0x32, 0xad, 0xf2, 0x39, 0x5f, 0xf2, 0x6d, 0x96, 0xe3, 0x60, 0x8b, 0x1c, 0x4e, 0x94, 0x9d, 0x52, 0x32, 0x25, 0x77, 0x6d, 0xe7, 0x19, 0x1c, 0x27, 0x33, 0x80, 0xb0, 0x70, 0x4e, 0xdd, - 0xec, 0x06, 0x3f, 0x28, 0xeb, 0x47, 0x4a, 0x20, 0x52, 0x4d, 0x72, 0x7e, 0x44, 0x70, 0xaf, 0x06, + 0xec, 0xde, 0x3f, 0x28, 0xeb, 0x47, 0x4a, 0x20, 0x52, 0x4d, 0x72, 0x7e, 0x44, 0x70, 0xaf, 0x06, 0xdb, 0x83, 0x90, 0x9b, 0x9e, 0xc2, 0xc6, 0xe6, 0xa7, 0xd0, 0x59, 0xc1, 0xfd, 0x2d, 0x63, 0x7e, 0x27, 0x91, 0x4a, 0xfb, 0x98, 0x6f, 0xda, 0x3e, 0x0f, 0x1f, 0x03, 0xae, 0x43, 0xb0, 0x05, 0x07, 0x63, 0x6f, 0xc1, 0xfd, 0xae, 0x81, 0x01, 0x0e, 0x5f, 0x08, 0x2e, 0x99, 0xe8, 0x22, 0xb5, 0x56, 0x7c, 0x99, 0xe8, 0x9a, 0x4f, 0x3e, 0xfa, 0xfd, 0xa6, 0x87, 0x5e, 0xdf, 0xf4, 0xd0, 0x3f, 0x37, 0x3d, 0xf4, 0xf3, 0x6d, 0xcf, 0x78, 0x7d, 0xdb, 0x33, 0xfe, 0xbe, 0xed, 0x19, 0xdf, 0x9f, 0x6c, - 0xfe, 0x3d, 0xf7, 0xf2, 0x50, 0x7f, 0x7c, 0xf2, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa5, 0x4a, - 0x77, 0x11, 0xf0, 0x09, 0x00, 0x00, + 0xfe, 0x3d, 0xf7, 0xf2, 0x50, 0x7f, 0x7c, 0xf2, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x80, 0xdf, + 0xf6, 0x6c, 0xf0, 0x09, 0x00, 0x00, } func (m *RawACLRecord) Marshal() (dAtA []byte, err error) { @@ -1752,7 +1752,7 @@ func (m *ACLUserRemove) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintAclrecord(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x1a + dAtA[i] = 0x12 } } if len(m.Identity) > 0 { @@ -4252,7 +4252,7 @@ func (m *ACLUserRemove) Unmarshal(dAtA []byte) error { m.Identity = []byte{} } iNdEx = postIndex - case 3: + case 2: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ReadKeyReplaces", wireType) } diff --git a/common/pkg/acl/aclrecordproto/protos/aclrecord.proto b/common/pkg/acl/aclrecordproto/protos/aclrecord.proto index 954796ed..bca03cd6 100644 --- a/common/pkg/acl/aclrecordproto/protos/aclrecord.proto +++ b/common/pkg/acl/aclrecordproto/protos/aclrecord.proto @@ -80,7 +80,7 @@ message ACLUserJoin { message ACLUserRemove { bytes identity = 1; - repeated ACLReadKeyReplace readKeyReplaces = 3; + repeated ACLReadKeyReplace readKeyReplaces = 2; } message ACLReadKeyReplace { diff --git a/common/pkg/acl/list/aclrecordbuilder.go b/common/pkg/acl/list/aclrecordbuilder.go index ac435a73..1448d460 100644 --- a/common/pkg/acl/list/aclrecordbuilder.go +++ b/common/pkg/acl/list/aclrecordbuilder.go @@ -7,6 +7,7 @@ import ( "github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/signingkey" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/symmetric" "github.com/gogo/protobuf/proto" + "time" ) type ACLRecordBuilder interface { @@ -35,7 +36,7 @@ func (a *aclRecordBuilder) BuildUserJoin(acceptPrivKeyBytes []byte, encSymKeyByt if err != nil { return } - encSymKey, err := symmetric.DeriveFromBytes(encSymKeyBytes) + encSymKey, err := symmetric.FromBytes(encSymKeyBytes) if err != nil { return } @@ -74,17 +75,31 @@ func (a *aclRecordBuilder) BuildUserJoin(acceptPrivKeyBytes []byte, encSymKeyByt AcceptPubKey: acceptPubKeyBytes, EncryptedReadKeys: symKeys, } - marshalledJoin, err := userJoin.Marshal() + aclData := &aclrecordproto.ACLData{AclContent: []*aclrecordproto.ACLContentValue{ + {Value: &aclrecordproto.ACLContentValue_UserJoin{UserJoin: userJoin}}, + }} + marshalledJoin, err := aclData.Marshal() if err != nil { return } - joinSignature, err := signPrivKey.Sign(marshalledJoin) + aclRecord := &aclrecordproto.ACLRecord{ + PrevId: state.LastRecordId(), + Identity: state.Identity(), + Data: marshalledJoin, + CurrentReadKeyHash: state.CurrentReadKeyHash(), + Timestamp: time.Now().UnixNano(), + } + marshalledRecord, err := aclRecord.Marshal() + if err != nil { + return + } + recSignature, err := signPrivKey.Sign(marshalledRecord) if err != nil { return } rec = &aclrecordproto.RawACLRecord{ - Payload: marshalledJoin, - Signature: joinSignature, + Payload: marshalledRecord, + Signature: recSignature, } return } diff --git a/common/pkg/acl/list/aclrecordbuilder_test.go b/common/pkg/acl/list/aclrecordbuilder_test.go new file mode 100644 index 00000000..42a9cbb7 --- /dev/null +++ b/common/pkg/acl/list/aclrecordbuilder_test.go @@ -0,0 +1,50 @@ +package list + +import ( + "context" + account "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/account" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/common" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/testutils/acllistbuilder" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/cid" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/signingkey" + "github.com/stretchr/testify/require" + "testing" +) + +func TestAclRecordBuilder_BuildUserJoin(t *testing.T) { + st, err := acllistbuilder.NewListStorageWithTestName("userjoinexample.yml") + require.NoError(t, err, "building storage should not result in error") + + keychain := st.(*acllistbuilder.ACLListStorageBuilder).GetKeychain() + identity := keychain.GeneratedIdentities["D"] + signPrivKey := keychain.SigningKeysByYAMLName["D"] + encPrivKey := keychain.EncryptionKeysByYAMLName["D"] + acc := &account.AccountData{ + Identity: []byte(identity), + SignKey: signPrivKey, + EncKey: encPrivKey, + } + + aclList, err := BuildACLListWithIdentity(acc, st) + require.NoError(t, err, "building acl list should be without error") + recordBuilder := newACLRecordBuilder(aclList.ID(), common.NewKeychain()) + rk, err := keychain.GetKey("key.Read.EncKey").(*acllistbuilder.SymKey).Key.Raw() + require.NoError(t, err) + privKey, err := keychain.GetKey("key.Sign.Onetime1").(signingkey.PrivKey).Raw() + require.NoError(t, err) + + userJoin, err := recordBuilder.BuildUserJoin(privKey, rk, aclList.ACLState()) + require.NoError(t, err) + marshalledJoin, err := userJoin.Marshal() + require.NoError(t, err) + id, err := cid.NewCIDFromBytes(marshalledJoin) + require.NoError(t, err) + rawRec := &aclrecordproto.RawACLRecordWithId{ + Payload: marshalledJoin, + Id: id, + } + err = aclList.AddRawRecords(context.Background(), []*aclrecordproto.RawACLRecordWithId{rawRec}) + require.NoError(t, err) + require.Equal(t, aclrecordproto.ACLUserPermissions_Writer, aclList.ACLState().UserStates()[identity].Permissions) +} diff --git a/common/pkg/acl/list/aclstate.go b/common/pkg/acl/list/aclstate.go index ec2bd7b7..94754aba 100644 --- a/common/pkg/acl/list/aclstate.go +++ b/common/pkg/acl/list/aclstate.go @@ -184,6 +184,7 @@ func (st *ACLState) applyRoot(root *aclrecordproto.ACLRoot) (err error) { EncryptionKey: root.EncryptionKey, Permissions: aclrecordproto.ACLUserPermissions_Admin, } + st.currentReadKeyHash = root.CurrentReadKeyHash st.userStates[string(root.Identity)] = userState st.totalReadKeys++ return @@ -192,13 +193,18 @@ func (st *ACLState) applyRoot(root *aclrecordproto.ACLRoot) (err error) { func (st *ACLState) saveReadKeyFromRoot(root *aclrecordproto.ACLRoot) (err error) { var readKey *symmetric.Key if len(root.GetDerivationScheme()) != 0 { - var encPubKey []byte - encPubKey, err = st.encryptionKey.GetPublic().Raw() + var encPrivKey []byte + encPrivKey, err = st.encryptionKey.Raw() + if err != nil { + return + } + var signPrivKey []byte + signPrivKey, err = st.signingKey.Raw() if err != nil { return } - readKey, err = aclrecordproto.ACLReadKeyDerive([]byte(st.identity), encPubKey) + readKey, err = aclrecordproto.ACLReadKeyDerive(signPrivKey, encPrivKey) if err != nil { return } @@ -217,7 +223,6 @@ func (st *ACLState) saveReadKeyFromRoot(root *aclrecordproto.ACLRoot) (err error if hasher.Sum64() != root.CurrentReadKeyHash { return ErrIncorrectRoot } - st.currentReadKeyHash = root.CurrentReadKeyHash st.userReadKeys[root.CurrentReadKeyHash] = readKey return @@ -451,3 +456,7 @@ func (st *ACLState) UserKeys() (encKey encryptionkey.PrivKey, signKey signingkey func (st *ACLState) Identity() []byte { return []byte(st.identity) } + +func (st *ACLState) LastRecordId() string { + return st.lastRecordId +} diff --git a/common/pkg/acl/testutils/acllistbuilder/keychain.go b/common/pkg/acl/testutils/acllistbuilder/keychain.go index db7fb0a6..ff0b9b04 100644 --- a/common/pkg/acl/testutils/acllistbuilder/keychain.go +++ b/common/pkg/acl/testutils/acllistbuilder/keychain.go @@ -16,28 +16,26 @@ type SymKey struct { } type YAMLKeychain struct { - SigningKeysByYAMLIdentity map[string]signingkey2.PrivKey - SigningKeysByRealIdentity map[string]signingkey2.PrivKey - EncryptionKeysByYAMLIdentity map[string]encryptionkey2.PrivKey - ReadKeysByYAMLIdentity map[string]*SymKey - ReadKeysByHash map[uint64]*SymKey - GeneratedIdentities map[string]string - DerivedIdentity string + SigningKeysByYAMLName map[string]signingkey2.PrivKey + SigningKeysByRealIdentity map[string]signingkey2.PrivKey + EncryptionKeysByYAMLName map[string]encryptionkey2.PrivKey + ReadKeysByYAMLName map[string]*SymKey + ReadKeysByHash map[uint64]*SymKey + GeneratedIdentities map[string]string } func NewKeychain() *YAMLKeychain { return &YAMLKeychain{ - SigningKeysByYAMLIdentity: map[string]signingkey2.PrivKey{}, - SigningKeysByRealIdentity: map[string]signingkey2.PrivKey{}, - EncryptionKeysByYAMLIdentity: map[string]encryptionkey2.PrivKey{}, - GeneratedIdentities: map[string]string{}, - ReadKeysByYAMLIdentity: map[string]*SymKey{}, - ReadKeysByHash: map[uint64]*SymKey{}, + SigningKeysByYAMLName: map[string]signingkey2.PrivKey{}, + SigningKeysByRealIdentity: map[string]signingkey2.PrivKey{}, + EncryptionKeysByYAMLName: map[string]encryptionkey2.PrivKey{}, + GeneratedIdentities: map[string]string{}, + ReadKeysByYAMLName: map[string]*SymKey{}, + ReadKeysByHash: map[uint64]*SymKey{}, } } func (k *YAMLKeychain) ParseKeys(keys *Keys) { - k.DerivedIdentity = keys.Derived for _, encKey := range keys.Enc { k.AddEncryptionKey(encKey) } @@ -52,7 +50,7 @@ func (k *YAMLKeychain) ParseKeys(keys *Keys) { } func (k *YAMLKeychain) AddEncryptionKey(key *Key) { - if _, exists := k.EncryptionKeysByYAMLIdentity[key.Name]; exists { + if _, exists := k.EncryptionKeysByYAMLName[key.Name]; exists { return } var ( @@ -70,11 +68,11 @@ func (k *YAMLKeychain) AddEncryptionKey(key *Key) { panic(err) } } - k.EncryptionKeysByYAMLIdentity[key.Name] = newPrivKey + k.EncryptionKeysByYAMLName[key.Name] = newPrivKey } func (k *YAMLKeychain) AddSigningKey(key *Key) { - if _, exists := k.SigningKeysByYAMLIdentity[key.Name]; exists { + if _, exists := k.SigningKeysByYAMLName[key.Name]; exists { return } var ( @@ -95,7 +93,7 @@ func (k *YAMLKeychain) AddSigningKey(key *Key) { pubKey = newPrivKey.GetPublic() } - k.SigningKeysByYAMLIdentity[key.Name] = newPrivKey + k.SigningKeysByYAMLName[key.Name] = newPrivKey rawPubKey, err := pubKey.Raw() if err != nil { panic(err) @@ -107,7 +105,7 @@ func (k *YAMLKeychain) AddSigningKey(key *Key) { } func (k *YAMLKeychain) AddReadKey(key *Key) { - if _, exists := k.ReadKeysByYAMLIdentity[key.Name]; exists { + if _, exists := k.ReadKeysByYAMLName[key.Name]; exists { return } @@ -121,8 +119,8 @@ func (k *YAMLKeychain) AddReadKey(key *Key) { panic("should be able to generate symmetric key") } } else if key.Value == "derived" { - signKey, _ := k.SigningKeysByYAMLIdentity[k.DerivedIdentity].Raw() - encKey, _ := k.EncryptionKeysByYAMLIdentity[k.DerivedIdentity].Raw() + signKey, _ := k.SigningKeysByYAMLName[key.Name].Raw() + encKey, _ := k.EncryptionKeysByYAMLName[key.Name].Raw() rkey, err = aclrecordproto.ACLReadKeyDerive(signKey, encKey) if err != nil { panic("should be able to derive symmetric key") @@ -137,7 +135,7 @@ func (k *YAMLKeychain) AddReadKey(key *Key) { hasher := fnv.New64() hasher.Write(rkey.Bytes()) - k.ReadKeysByYAMLIdentity[key.Name] = &SymKey{ + k.ReadKeysByYAMLName[key.Name] = &SymKey{ Hash: hasher.Sum64(), Key: rkey, } @@ -174,15 +172,15 @@ func (k *YAMLKeychain) GetKey(key string) interface{} { switch parts[1] { case "Sign": - if key, exists := k.SigningKeysByYAMLIdentity[name]; exists { + if key, exists := k.SigningKeysByYAMLName[name]; exists { return key } case "Enc": - if key, exists := k.EncryptionKeysByYAMLIdentity[name]; exists { + if key, exists := k.EncryptionKeysByYAMLName[name]; exists { return key } case "Read": - if key, exists := k.ReadKeysByYAMLIdentity[name]; exists { + if key, exists := k.ReadKeysByYAMLName[name]; exists { return key } default: diff --git a/common/pkg/acl/testutils/acllistbuilder/liststoragebuilder.go b/common/pkg/acl/testutils/acllistbuilder/liststoragebuilder.go index 25542e93..a1309073 100644 --- a/common/pkg/acl/testutils/acllistbuilder/liststoragebuilder.go +++ b/common/pkg/acl/testutils/acllistbuilder/liststoragebuilder.go @@ -10,7 +10,6 @@ import ( "github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/encryptionkey" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/signingkey" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/symmetric" - "hash/fnv" "io/ioutil" "path" "time" @@ -127,7 +126,7 @@ func (t *ACLListStorageBuilder) parseRecord(rec *Record, prevId string) *aclreco Identity: []byte(t.keychain.GetIdentity(rec.Identity)), Data: bytes, CurrentReadKeyHash: k.Hash, - Timestamp: time.Now().Unix(), + Timestamp: time.Now().UnixNano(), } } @@ -155,7 +154,7 @@ func (t *ACLListStorageBuilder) parseACLChange(ch *ACLChange) (convCh *aclrecord encKey := t.keychain.GetKey(join.EncryptionKey).(encryptionkey.PrivKey) rawKey, _ := encKey.GetPublic().Raw() - idKey, _ := t.keychain.SigningKeysByYAMLIdentity[join.Identity].GetPublic().Raw() + idKey, _ := t.keychain.SigningKeysByYAMLName[join.Identity].GetPublic().Raw() signKey := t.keychain.GetKey(join.AcceptKey).(signingkey.PrivKey) signature, err := signKey.Sign(idKey) if err != nil { @@ -208,7 +207,7 @@ func (t *ACLListStorageBuilder) parseACLChange(ch *ACLChange) (convCh *aclrecord var replaces []*aclrecordproto.ACLReadKeyReplace for _, id := range remove.IdentitiesLeft { - encKey := t.keychain.EncryptionKeysByYAMLIdentity[id] + encKey := t.keychain.EncryptionKeysByYAMLName[id] rawEncKey, _ := encKey.GetPublic().Raw() encReadKey, err := encKey.GetPublic().Encrypt(newReadKey.Key.Bytes()) if err != nil { @@ -281,18 +280,16 @@ func (t *ACLListStorageBuilder) traverseFromHead(f func(rec *aclrecordproto.ACLR } func (t *ACLListStorageBuilder) parseRoot(root *Root) (rawRoot *aclrecordproto.RawACLRecordWithId) { - rawSignKey, _ := t.keychain.SigningKeysByYAMLIdentity[root.Identity].GetPublic().Raw() - rawEncKey, _ := t.keychain.EncryptionKeysByYAMLIdentity[root.Identity].GetPublic().Raw() - readKey, _ := aclrecordproto.ACLReadKeyDerive(rawSignKey, rawEncKey) - hasher := fnv.New64() - hasher.Write(readKey.Bytes()) + rawSignKey, _ := t.keychain.SigningKeysByYAMLName[root.Identity].GetPublic().Raw() + rawEncKey, _ := t.keychain.EncryptionKeysByYAMLName[root.Identity].GetPublic().Raw() + readKey := t.keychain.ReadKeysByYAMLName[root.Identity] aclRoot := &aclrecordproto.ACLRoot{ Identity: rawSignKey, EncryptionKey: rawEncKey, SpaceId: root.SpaceId, EncryptedReadKey: nil, DerivationScheme: "scheme", - CurrentReadKeyHash: hasher.Sum64(), + CurrentReadKeyHash: readKey.Hash, } return t.createRaw(aclRoot, rawSignKey) } diff --git a/common/pkg/acl/testutils/yamltests/userjoinexample.yml b/common/pkg/acl/testutils/yamltests/userjoinexample.yml index c78670e6..fd90c063 100644 --- a/common/pkg/acl/testutils/yamltests/userjoinexample.yml +++ b/common/pkg/acl/testutils/yamltests/userjoinexample.yml @@ -7,24 +7,23 @@ records: - userInvite: acceptKey: key.Sign.Onetime1 encryptionKey: key.Read.EncKey - encryptedReadKeys: [key.Read.1] + encryptedReadKeys: [key.Read.A] permissions: writer - userAdd: identity: C permission: reader encryptionKey: key.Enc.C - encryptedReadKeys: [key.Read.1] - readKey: key.Read.1 + encryptedReadKeys: [key.Read.A] + readKey: key.Read.A - identity: B aclChanges: - userJoin: identity: B encryptionKey: key.Enc.B acceptKey: key.Sign.Onetime1 - encryptedReadKeys: [key.Read.1] - readKey: key.Read.1 + encryptedReadKeys: [key.Read.A] + readKey: key.Read.A keys: - Derived: A Enc: - name: A value: generated @@ -32,6 +31,8 @@ keys: value: generated - name: C value: generated + - name: D + value: generated - name: Onetime1 value: generated Sign: @@ -41,10 +42,12 @@ keys: value: generated - name: C value: generated + - name: D + value: generated - name: Onetime1 value: generated Read: - - name: 1 + - name: A value: derived - name: EncKey value: generated diff --git a/common/pkg/acl/testutils/yamltests/userremoveexample.yml b/common/pkg/acl/testutils/yamltests/userremoveexample.yml index 9335f839..cc6d817e 100644 --- a/common/pkg/acl/testutils/yamltests/userremoveexample.yml +++ b/common/pkg/acl/testutils/yamltests/userremoveexample.yml @@ -7,22 +7,22 @@ records: - userInvite: acceptKey: key.Sign.Onetime1 encryptionKey: key.Read.EncKey - encryptedReadKeys: [key.Read.1] + encryptedReadKeys: [key.Read.A] permissions: writer - userAdd: identity: C permission: reader encryptionKey: key.Enc.C - encryptedReadKeys: [key.Read.1] - readKey: key.Read.1 + encryptedReadKeys: [key.Read.A] + readKey: key.Read.A - identity: B aclChanges: - userJoin: identity: B encryptionKey: key.Enc.B acceptKey: key.Sign.Onetime1 - encryptedReadKeys: [key.Read.1] - readKey: key.Read.1 + encryptedReadKeys: [key.Read.A] + readKey: key.Read.A - identity: A aclChanges: - userRemove: @@ -31,7 +31,6 @@ records: identitiesLeft: [A, C] readKey: key.Read.2 keys: - Derived: A Enc: - name: A value: generated @@ -51,7 +50,7 @@ keys: - name: Onetime1 value: generated Read: - - name: 1 + - name: A value: derived - name: 2 value: generated