diff --git a/commonspace/payloads.go b/commonspace/payloads.go index 46d2515d..4d601155 100644 --- a/commonspace/payloads.go +++ b/commonspace/payloads.go @@ -1,14 +1,20 @@ package commonspace import ( + "fmt" + "github.com/anytypeio/any-sync/commonspace/object/acl/aclrecordproto" "github.com/anytypeio/any-sync/commonspace/object/acl/list" "github.com/anytypeio/any-sync/commonspace/object/tree/objecttree" + "github.com/anytypeio/any-sync/commonspace/object/tree/treechangeproto" "github.com/anytypeio/any-sync/commonspace/spacestorage" "github.com/anytypeio/any-sync/commonspace/spacesyncproto" "github.com/anytypeio/any-sync/util/cidutil" "github.com/anytypeio/any-sync/util/crypto" + "github.com/gogo/protobuf/proto" "hash/fnv" "math/rand" + "strconv" + "strings" "time" ) @@ -180,3 +186,177 @@ func storagePayloadForSpaceDerive(payload SpaceDerivePayload) (storagePayload sp } return } + +func validateSpaceStorageCreatePayload(payload spacestorage.SpaceStorageCreatePayload) (err error) { + err = validateCreateSpaceHeaderPayload(payload.SpaceHeaderWithId) + if err != nil { + return + } + aclSpaceId, err := validateCreateSpaceAclPayload(payload.AclWithId) + if err != nil { + return + } + aclHeadId, settingsSpaceId, err := validateCreateSpaceSettingsPayload(payload.SpaceSettingsWithId) + if err != nil { + return + } + if aclSpaceId != payload.SpaceHeaderWithId.Id || aclSpaceId != settingsSpaceId { + err = spacestorage.ErrIncorrectSpaceHeader + return + } + if aclHeadId != payload.AclWithId.Id { + err = spacestorage.ErrIncorrectSpaceHeader + return + } + return +} + +func validateCreateSpaceHeaderPayload(rawHeaderWithId *spacesyncproto.RawSpaceHeaderWithId) (err error) { + var rawSpaceHeader spacesyncproto.RawSpaceHeader + err = proto.Unmarshal(rawHeaderWithId.RawHeader, &rawSpaceHeader) + if err != nil { + return + } + var header spacesyncproto.SpaceHeader + err = proto.Unmarshal(rawSpaceHeader.SpaceHeader, &header) + if err != nil { + return + } + split := strings.Split(rawHeaderWithId.Id, ".") + if len(split) != 2 { + return spacestorage.ErrIncorrectSpaceHeader + } + if !cidutil.VerifyCid(rawHeaderWithId.RawHeader, split[0]) { + err = objecttree.ErrIncorrectCid + return + } + payloadIdentity, err := crypto.UnmarshalEd25519PublicKeyProto(header.Identity) + if err != nil { + return + } + res, err := payloadIdentity.Verify(rawSpaceHeader.SpaceHeader, rawSpaceHeader.Signature) + if err != nil || !res { + err = spacestorage.ErrIncorrectSpaceHeader + return + } + id, err := cidutil.NewCidFromBytes(rawHeaderWithId.RawHeader) + if err != nil { + return + } + requiredSpaceId := fmt.Sprintf("%s.%s", id, strconv.FormatUint(header.ReplicationKey, 36)) + if requiredSpaceId != rawHeaderWithId.Id { + err = spacestorage.ErrIncorrectSpaceHeader + return + } + + return +} + +func validateCreateSpaceAclPayload(rawWithId *aclrecordproto.RawAclRecordWithId) (spaceId string, err error) { + if !cidutil.VerifyCid(rawWithId.Payload, rawWithId.Id) { + err = objecttree.ErrIncorrectCid + return + } + var rawAcl aclrecordproto.RawAclRecord + err = proto.Unmarshal(rawWithId.Payload, &rawAcl) + if err != nil { + return + } + var aclRoot aclrecordproto.AclRoot + err = proto.Unmarshal(rawAcl.Payload, &aclRoot) + if err != nil { + return + } + payloadIdentity, err := crypto.UnmarshalEd25519PublicKeyProto(aclRoot.Identity) + if err != nil { + return + } + res, err := payloadIdentity.Verify(rawAcl.Payload, rawAcl.Signature) + if err != nil || !res { + err = spacestorage.ErrIncorrectSpaceHeader + return + } + masterKey, err := crypto.UnmarshalEd25519PublicKeyProto(aclRoot.MasterKey) + if err != nil { + return + } + rawIdentity, err := payloadIdentity.Raw() + if err != nil { + return + } + res, err = masterKey.Verify(rawIdentity, aclRoot.IdentitySignature) + if err != nil || !res { + err = spacestorage.ErrIncorrectSpaceHeader + return + } + spaceId = aclRoot.SpaceId + + return +} + +func validateCreateSpaceSettingsPayload(rawWithId *treechangeproto.RawTreeChangeWithId) (aclHeadId string, spaceId string, err error) { + var raw treechangeproto.RawTreeChange + err = proto.Unmarshal(rawWithId.RawChange, &raw) + if err != nil { + return + } + var rootChange treechangeproto.RootChange + err = proto.Unmarshal(raw.Payload, &rootChange) + if err != nil { + return + } + payloadIdentity, err := crypto.UnmarshalEd25519PublicKeyProto(rootChange.Identity) + if err != nil { + return + } + res, err := payloadIdentity.Verify(raw.Payload, raw.Signature) + if err != nil || !res { + err = spacestorage.ErrIncorrectSpaceHeader + return + } + id, err := cidutil.NewCidFromBytes(rawWithId.RawChange) + if id != rawWithId.Id { + err = spacestorage.ErrIncorrectSpaceHeader + return + } + spaceId = rootChange.SpaceId + aclHeadId = rootChange.AclHeadId + + return +} + +// ValidateSpaceHeader Used in coordinator +func ValidateSpaceHeader(spaceId string, header []byte, identity crypto.PubKey) (err error) { + split := strings.Split(spaceId, ".") + if len(split) != 2 { + return spacestorage.ErrIncorrectSpaceHeader + } + if !cidutil.VerifyCid(header, split[0]) { + err = objecttree.ErrIncorrectCid + return + } + raw := &spacesyncproto.RawSpaceHeader{} + err = proto.Unmarshal(header, raw) + if err != nil { + return + } + payload := &spacesyncproto.SpaceHeader{} + err = proto.Unmarshal(raw.SpaceHeader, payload) + if err != nil { + return + } + payloadIdentity, err := crypto.UnmarshalEd25519PublicKeyProto(payload.Identity) + if err != nil { + return + } + if identity != nil && !payloadIdentity.Equals(identity) { + err = spacestorage.ErrIncorrectSpaceHeader + return + } + res, err := identity.Verify(raw.SpaceHeader, raw.Signature) + if err != nil || !res { + err = spacestorage.ErrIncorrectSpaceHeader + return + } + return +} diff --git a/commonspace/payloads_test.go b/commonspace/payloads_test.go new file mode 100644 index 00000000..13535b34 --- /dev/null +++ b/commonspace/payloads_test.go @@ -0,0 +1,655 @@ +package commonspace + +import ( + "fmt" + "github.com/anytypeio/any-sync/commonspace/object/accountdata" + "github.com/anytypeio/any-sync/commonspace/object/acl/aclrecordproto" + "github.com/anytypeio/any-sync/commonspace/object/tree/objecttree" + "github.com/anytypeio/any-sync/commonspace/object/tree/treechangeproto" + "github.com/anytypeio/any-sync/commonspace/spacestorage" + "github.com/anytypeio/any-sync/commonspace/spacesyncproto" + "github.com/anytypeio/any-sync/util/cidutil" + "github.com/anytypeio/any-sync/util/crypto" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "math/rand" + "strconv" + "testing" + "time" +) + +func TestSuccessHeaderPayloadForSpaceCreate(t *testing.T) { + accountKeys, err := accountdata.NewRandom() + require.NoError(t, err) + _, rawHeaderWithId, err := rawHeaderWithId(accountKeys) + require.NoError(t, err) + err = validateCreateSpaceHeaderPayload(rawHeaderWithId) + require.NoError(t, err) +} + +func TestFailedHeaderPayloadForSpaceCreate_InvalidFormatSpaceId(t *testing.T) { + accountKeys, err := accountdata.NewRandom() + require.NoError(t, err) + identity, err := accountKeys.SignKey.GetPublic().Marshall() + require.NoError(t, err) + spaceHeaderSeed := make([]byte, 32) + _, err = rand.Read(spaceHeaderSeed) + require.NoError(t, err) + spaceHeaderPayload := make([]byte, 32) + _, err = rand.Read(spaceHeaderPayload) + require.NoError(t, err) + replicationKey := rand.Uint64() + header := &spacesyncproto.SpaceHeader{ + Identity: identity, + Timestamp: time.Now().Unix(), + SpaceType: "SpaceType", + ReplicationKey: replicationKey, + Seed: spaceHeaderSeed, + SpaceHeaderPayload: spaceHeaderPayload, + } + marhalled, err := header.Marshal() + require.NoError(t, err) + signature, err := accountKeys.SignKey.Sign(marhalled) + require.NoError(t, err) + rawHeader := &spacesyncproto.RawSpaceHeader{ + SpaceHeader: marhalled, + Signature: signature, + } + marhalledRawHeader, err := rawHeader.Marshal() + require.NoError(t, err) + id, err := cidutil.NewCidFromBytes(marhalled) + require.NoError(t, err) + spaceId := fmt.Sprintf("%s%s", id, strconv.FormatUint(replicationKey, 36)) + rawHeaderWithId := &spacesyncproto.RawSpaceHeaderWithId{ + RawHeader: marhalledRawHeader, + Id: spaceId, + } + err = validateCreateSpaceHeaderPayload(rawHeaderWithId) + assert.EqualErrorf(t, err, spacestorage.ErrIncorrectSpaceHeader.Error(), "Error should be: %v, got: %v", spacestorage.ErrIncorrectSpaceHeader, err) +} + +func TestFailedHeaderPayloadForSpaceCreate_CidIsWrong(t *testing.T) { + accountKeys, err := accountdata.NewRandom() + require.NoError(t, err) + identity, err := accountKeys.SignKey.GetPublic().Marshall() + require.NoError(t, err) + spaceHeaderSeed := make([]byte, 32) + _, err = rand.Read(spaceHeaderSeed) + require.NoError(t, err) + spaceHeaderPayload := make([]byte, 32) + _, err = rand.Read(spaceHeaderPayload) + require.NoError(t, err) + replicationKey := rand.Uint64() + header := &spacesyncproto.SpaceHeader{ + Identity: identity, + Timestamp: time.Now().Unix(), + SpaceType: "SpaceType", + ReplicationKey: replicationKey, + Seed: spaceHeaderSeed, + SpaceHeaderPayload: spaceHeaderPayload, + } + marhalled, err := header.Marshal() + require.NoError(t, err) + signature, err := accountKeys.SignKey.Sign(marhalled) + require.NoError(t, err) + rawHeader := &spacesyncproto.RawSpaceHeader{ + SpaceHeader: marhalled, + Signature: signature, + } + marhalledRawHeader, err := rawHeader.Marshal() + require.NoError(t, err) + id := "faisdfjpiocpoakopkop34" + spaceId := fmt.Sprintf("%s.%s", id, strconv.FormatUint(replicationKey, 36)) + rawHeaderWithId := &spacesyncproto.RawSpaceHeaderWithId{ + RawHeader: marhalledRawHeader, + Id: spaceId, + } + err = validateCreateSpaceHeaderPayload(rawHeaderWithId) + assert.EqualErrorf(t, err, objecttree.ErrIncorrectCid.Error(), "Error should be: %v, got: %v", objecttree.ErrIncorrectCid, err) +} + +func TestFailedHeaderPayloadForSpaceCreate_SignedWithAnotherIdentity(t *testing.T) { + accountKeys, err := accountdata.NewRandom() + require.NoError(t, err) + identity, err := accountKeys.SignKey.GetPublic().Marshall() + require.NoError(t, err) + spaceHeaderSeed := make([]byte, 32) + _, err = rand.Read(spaceHeaderSeed) + require.NoError(t, err) + spaceHeaderPayload := make([]byte, 32) + _, err = rand.Read(spaceHeaderPayload) + require.NoError(t, err) + replicationKey := rand.Uint64() + header := &spacesyncproto.SpaceHeader{ + Identity: identity, + Timestamp: time.Now().Unix(), + SpaceType: "SpaceType", + ReplicationKey: replicationKey, + Seed: spaceHeaderSeed, + SpaceHeaderPayload: spaceHeaderPayload, + } + marhalled, err := header.Marshal() + require.NoError(t, err) + anotherAccountKeys, err := accountdata.NewRandom() + signature, err := anotherAccountKeys.SignKey.Sign(marhalled) + require.NoError(t, err) + rawHeader := &spacesyncproto.RawSpaceHeader{ + SpaceHeader: marhalled, + Signature: signature, + } + marhalledRawHeader, err := rawHeader.Marshal() + require.NoError(t, err) + id := "faisdfjpiocpoakopkop34" + spaceId := fmt.Sprintf("%s.%s", id, strconv.FormatUint(replicationKey, 36)) + rawHeaderWithId := &spacesyncproto.RawSpaceHeaderWithId{ + RawHeader: marhalledRawHeader, + Id: spaceId, + } + err = validateCreateSpaceHeaderPayload(rawHeaderWithId) + assert.EqualErrorf(t, err, objecttree.ErrIncorrectCid.Error(), "Error should be: %v, got: %v", objecttree.ErrIncorrectCid, err) +} + +func TestSuccessAclPayloadSpace(t *testing.T) { + accountKeys, err := accountdata.NewRandom() + spaceId := "AnySpaceId" + _, rawWithId, err := rawAclWithId(accountKeys, spaceId) + require.NoError(t, err) + validationSpaceId, err := validateCreateSpaceAclPayload(rawWithId) + require.Equal(t, validationSpaceId, spaceId) + require.NoError(t, err) +} + +func TestFailAclPayloadSpace_IncorrectCid(t *testing.T) { + accountKeys, err := accountdata.NewRandom() + require.NoError(t, err) + identity, err := accountKeys.SignKey.GetPublic().Marshall() + require.NoError(t, err) + readKeyBytes := make([]byte, 32) + _, err = rand.Read(readKeyBytes) + require.NoError(t, err) + readKey, err := accountKeys.SignKey.GetPublic().Encrypt(readKeyBytes) + require.NoError(t, err) + masterKey, _, err := crypto.GenerateRandomEd25519KeyPair() + require.NoError(t, err) + rawIdentity, err := accountKeys.SignKey.GetPublic().Raw() + require.NoError(t, err) + identitySignature, err := masterKey.Sign(rawIdentity) + require.NoError(t, err) + rawMasterKey, err := masterKey.GetPublic().Marshall() + require.NoError(t, err) + aclRoot := aclrecordproto.AclRoot{ + Identity: identity, + MasterKey: rawMasterKey, + SpaceId: "SpaceId", + EncryptedReadKey: readKey, + Timestamp: time.Now().Unix(), + IdentitySignature: identitySignature, + } + marshalled, err := aclRoot.Marshal() + require.NoError(t, err) + signature, err := accountKeys.SignKey.Sign(marshalled) + rawAclRecord := &aclrecordproto.RawAclRecord{ + Payload: marshalled, + Signature: signature, + } + marshalledRaw, err := rawAclRecord.Marshal() + require.NoError(t, err) + aclHeadId := "rand" + rawWithId := &aclrecordproto.RawAclRecordWithId{ + Payload: marshalledRaw, + Id: aclHeadId, + } + _, err = validateCreateSpaceAclPayload(rawWithId) + assert.EqualErrorf(t, err, objecttree.ErrIncorrectCid.Error(), "Error should be: %v, got: %v", objecttree.ErrIncorrectCid, err) +} + +func TestFailedAclPayloadSpace_IncorrectSignature(t *testing.T) { + accountKeys, err := accountdata.NewRandom() + require.NoError(t, err) + readKeyBytes := make([]byte, 32) + _, err = rand.Read(readKeyBytes) + require.NoError(t, err) + readKey, err := accountKeys.SignKey.GetPublic().Encrypt(readKeyBytes) + require.NoError(t, err) + masterKey, _, err := crypto.GenerateRandomEd25519KeyPair() + require.NoError(t, err) + rawIdentity, err := accountKeys.SignKey.GetPublic().Raw() + require.NoError(t, err) + identity, err := accountKeys.SignKey.GetPublic().Marshall() + identitySignature, err := masterKey.Sign(rawIdentity) + require.NoError(t, err) + rawMasterKey, err := masterKey.GetPublic().Raw() + require.NoError(t, err) + aclRoot := aclrecordproto.AclRoot{ + Identity: identity, + MasterKey: rawMasterKey, + SpaceId: "SpaceId", + EncryptedReadKey: readKey, + Timestamp: time.Now().Unix(), + IdentitySignature: identitySignature, + } + marshalled, err := aclRoot.Marshal() + require.NoError(t, err) + rawAclRecord := &aclrecordproto.RawAclRecord{ + Payload: marshalled, + Signature: marshalled, + } + marshalledRaw, err := rawAclRecord.Marshal() + require.NoError(t, err) + aclHeadId, err := cidutil.NewCidFromBytes(marshalledRaw) + require.NoError(t, err) + rawWithId := &aclrecordproto.RawAclRecordWithId{ + Payload: marshalledRaw, + Id: aclHeadId, + } + _, err = validateCreateSpaceAclPayload(rawWithId) + assert.NotNil(t, err) + assert.EqualErrorf(t, err, spacestorage.ErrIncorrectSpaceHeader.Error(), "Error should be: %v, got: %v", spacestorage.ErrIncorrectSpaceHeader, err) +} + +func TestFailedAclPayloadSpace_IncorrectIdentitySignature(t *testing.T) { + spaceId := "AnySpaceId" + accountKeys, err := accountdata.NewRandom() + require.NoError(t, err) + readKeyBytes := make([]byte, 32) + _, err = rand.Read(readKeyBytes) + if err != nil { + return + } + readKey, err := accountKeys.SignKey.GetPublic().Encrypt(readKeyBytes) + if err != nil { + return + } + masterKey, _, err := crypto.GenerateRandomEd25519KeyPair() + if err != nil { + return + } + masterPubKey := masterKey.GetPublic() + identity, err := accountKeys.SignKey.GetPublic().Marshall() + if err != nil { + return + } + rawMasterKey, err := masterPubKey.Marshall() + if err != nil { + return + } + aclRoot := aclrecordproto.AclRoot{ + Identity: identity, + MasterKey: rawMasterKey, + SpaceId: spaceId, + EncryptedReadKey: readKey, + Timestamp: time.Now().Unix(), + IdentitySignature: identity, + } + marshalled, err := aclRoot.Marshal() + if err != nil { + return + } + signature, err := accountKeys.SignKey.Sign(marshalled) + rawAclRecord := &aclrecordproto.RawAclRecord{ + Payload: marshalled, + Signature: signature, + } + marshalledRaw, err := rawAclRecord.Marshal() + if err != nil { + return + } + aclHeadId, err := cidutil.NewCidFromBytes(marshalledRaw) + if err != nil { + return + } + rawWithId := &aclrecordproto.RawAclRecordWithId{ + Payload: marshalledRaw, + Id: aclHeadId, + } + _, err = validateCreateSpaceAclPayload(rawWithId) + assert.EqualErrorf(t, err, spacestorage.ErrIncorrectSpaceHeader.Error(), "Error should be: %v, got: %v", spacestorage.ErrIncorrectSpaceHeader, err) +} + +func TestSuccessSettingsPayloadSpace(t *testing.T) { + accountKeys, err := accountdata.NewRandom() + require.NoError(t, err) + identity, err := accountKeys.SignKey.GetPublic().Marshall() + require.NoError(t, err) + spaceSettingsSeed := make([]byte, 32) + _, err = rand.Read(spaceSettingsSeed) + require.NoError(t, err) + changePayload := make([]byte, 32) + _, err = rand.Read(changePayload) + require.NoError(t, err) + spaceId := "SpaceId" + rootChange := &treechangeproto.RootChange{ + AclHeadId: "AclHeadId", + SpaceId: spaceId, + ChangeType: "ChangeType", + Timestamp: time.Now().Unix(), + Seed: spaceSettingsSeed, + Identity: identity, + ChangePayload: changePayload, + } + marshalledChange, err := rootChange.Marshal() + require.NoError(t, err) + signature, err := accountKeys.SignKey.Sign(marshalledChange) + require.NoError(t, err) + raw := &treechangeproto.RawTreeChange{ + Payload: marshalledChange, + Signature: signature, + } + marshalledRawChange, err := raw.Marshal() + id, err := cidutil.NewCidFromBytes(marshalledRawChange) + require.NoError(t, err) + rawIdChange := &treechangeproto.RawTreeChangeWithId{ + RawChange: marshalledRawChange, + Id: id, + } + _, validationSpaceId, err := validateCreateSpaceSettingsPayload(rawIdChange) + require.Equal(t, validationSpaceId, spaceId) + require.NoError(t, err) +} + +func TestFailSettingsPayloadSpace_InvalidSignature(t *testing.T) { + accountKeys, err := accountdata.NewRandom() + require.NoError(t, err) + identity, err := accountKeys.SignKey.GetPublic().Marshall() + require.NoError(t, err) + spaceSettingsSeed := make([]byte, 32) + _, err = rand.Read(spaceSettingsSeed) + require.NoError(t, err) + changePayload := make([]byte, 32) + _, err = rand.Read(changePayload) + require.NoError(t, err) + rootChange := &treechangeproto.RootChange{ + AclHeadId: "AclHeadId", + SpaceId: "SpaceId", + ChangeType: "ChangeType", + Timestamp: time.Now().Unix(), + Seed: spaceSettingsSeed, + Identity: identity, + ChangePayload: changePayload, + } + marshalledChange, err := rootChange.Marshal() + require.NoError(t, err) + raw := &treechangeproto.RawTreeChange{ + Payload: marshalledChange, + Signature: marshalledChange, + } + marshalledRawChange, err := raw.Marshal() + id, err := cidutil.NewCidFromBytes(marshalledRawChange) + require.NoError(t, err) + rawIdChange := &treechangeproto.RawTreeChangeWithId{ + RawChange: marshalledRawChange, + Id: id, + } + _, _, err = validateCreateSpaceSettingsPayload(rawIdChange) + assert.EqualErrorf(t, err, spacestorage.ErrIncorrectSpaceHeader.Error(), "Error should be: %v, got: %v", spacestorage.ErrIncorrectSpaceHeader, err) +} + +func TestFailSettingsPayloadSpace_InvalidCid(t *testing.T) { + accountKeys, err := accountdata.NewRandom() + require.NoError(t, err) + identity, err := accountKeys.SignKey.GetPublic().Marshall() + require.NoError(t, err) + spaceSettingsSeed := make([]byte, 32) + _, err = rand.Read(spaceSettingsSeed) + require.NoError(t, err) + changePayload := make([]byte, 32) + _, err = rand.Read(changePayload) + require.NoError(t, err) + rootChange := &treechangeproto.RootChange{ + AclHeadId: "AclHeadId", + SpaceId: "SpaceId", + ChangeType: "ChangeType", + Timestamp: time.Now().Unix(), + Seed: spaceSettingsSeed, + Identity: identity, + ChangePayload: changePayload, + } + marshalledChange, err := rootChange.Marshal() + require.NoError(t, err) + signature, err := accountKeys.SignKey.Sign(marshalledChange) + require.NoError(t, err) + raw := &treechangeproto.RawTreeChange{ + Payload: marshalledChange, + Signature: signature, + } + marshalledRawChange, err := raw.Marshal() + id := "id" + require.NoError(t, err) + rawIdChange := &treechangeproto.RawTreeChangeWithId{ + RawChange: marshalledRawChange, + Id: id, + } + _, _, err = validateCreateSpaceSettingsPayload(rawIdChange) + assert.EqualErrorf(t, err, spacestorage.ErrIncorrectSpaceHeader.Error(), "Error should be: %v, got: %v", spacestorage.ErrIncorrectSpaceHeader, err) +} + +func TestSuccessSameIds(t *testing.T) { + accountKeys, err := accountdata.NewRandom() + require.NoError(t, err) + spaceId, rawHeaderWithId, err := rawHeaderWithId(accountKeys) + require.NoError(t, err) + aclHeadId, rawAclWithId, err := rawAclWithId(accountKeys, spaceId) + require.NoError(t, err) + rawSettingsPayload, err := rawSettingsPayload(accountKeys, spaceId, aclHeadId) + spacePayload := spacestorage.SpaceStorageCreatePayload{ + AclWithId: rawAclWithId, + SpaceHeaderWithId: rawHeaderWithId, + SpaceSettingsWithId: rawSettingsPayload, + } + err = validateSpaceStorageCreatePayload(spacePayload) + require.NoError(t, err) +} + +func TestFailWithAclWrongSpaceId(t *testing.T) { + accountKeys, err := accountdata.NewRandom() + require.NoError(t, err) + spaceId, rawHeaderWithId, err := rawHeaderWithId(accountKeys) + require.NoError(t, err) + aclHeadId, rawAclWithId, err := rawAclWithId(accountKeys, "spaceId") + require.NoError(t, err) + rawSettingsPayload, err := rawSettingsPayload(accountKeys, spaceId, aclHeadId) + spacePayload := spacestorage.SpaceStorageCreatePayload{ + AclWithId: rawAclWithId, + SpaceHeaderWithId: rawHeaderWithId, + SpaceSettingsWithId: rawSettingsPayload, + } + err = validateSpaceStorageCreatePayload(spacePayload) + assert.EqualErrorf(t, err, spacestorage.ErrIncorrectSpaceHeader.Error(), "Error should be: %v, got: %v", spacestorage.ErrIncorrectSpaceHeader, err) +} + +func TestFailWithSettingsWrongSpaceId(t *testing.T) { + accountKeys, err := accountdata.NewRandom() + require.NoError(t, err) + spaceId, rawHeaderWithId, err := rawHeaderWithId(accountKeys) + require.NoError(t, err) + aclHeadId, rawAclWithId, err := rawAclWithId(accountKeys, spaceId) + require.NoError(t, err) + rawSettingsPayload, err := rawSettingsPayload(accountKeys, "spaceId", aclHeadId) + spacePayload := spacestorage.SpaceStorageCreatePayload{ + AclWithId: rawAclWithId, + SpaceHeaderWithId: rawHeaderWithId, + SpaceSettingsWithId: rawSettingsPayload, + } + err = validateSpaceStorageCreatePayload(spacePayload) + assert.EqualErrorf(t, err, spacestorage.ErrIncorrectSpaceHeader.Error(), "Error should be: %v, got: %v", spacestorage.ErrIncorrectSpaceHeader, err) +} + +func TestFailWithWrongAclHeadIdInSettingsPayload(t *testing.T) { + accountKeys, err := accountdata.NewRandom() + require.NoError(t, err) + spaceId, rawHeaderWithId, err := rawHeaderWithId(accountKeys) + require.NoError(t, err) + _, rawAclWithId, err := rawAclWithId(accountKeys, spaceId) + require.NoError(t, err) + rawSettingsPayload, err := rawSettingsPayload(accountKeys, spaceId, "aclHeadId") + spacePayload := spacestorage.SpaceStorageCreatePayload{ + AclWithId: rawAclWithId, + SpaceHeaderWithId: rawHeaderWithId, + SpaceSettingsWithId: rawSettingsPayload, + } + err = validateSpaceStorageCreatePayload(spacePayload) + assert.EqualErrorf(t, err, spacestorage.ErrIncorrectSpaceHeader.Error(), "Error should be: %v, got: %v", spacestorage.ErrIncorrectSpaceHeader, err) +} + +func rawSettingsPayload(accountKeys *accountdata.AccountKeys, spaceId, aclHeadId string) (rawIdChange *treechangeproto.RawTreeChangeWithId, err error) { + identity, err := accountKeys.SignKey.GetPublic().Marshall() + if err != nil { + return + } + spaceSettingsSeed := make([]byte, 32) + _, err = rand.Read(spaceSettingsSeed) + if err != nil { + return + } + changePayload := make([]byte, 32) + _, err = rand.Read(changePayload) + if err != nil { + return + } + rootChange := &treechangeproto.RootChange{ + AclHeadId: aclHeadId, + SpaceId: spaceId, + ChangeType: "ChangeType", + Timestamp: time.Now().Unix(), + Seed: spaceSettingsSeed, + Identity: identity, + ChangePayload: changePayload, + } + marshalledChange, err := rootChange.Marshal() + if err != nil { + return + } + signature, err := accountKeys.SignKey.Sign(marshalledChange) + if err != nil { + return + } + raw := &treechangeproto.RawTreeChange{ + Payload: marshalledChange, + Signature: signature, + } + marshalledRawChange, err := raw.Marshal() + id, err := cidutil.NewCidFromBytes(marshalledRawChange) + if err != nil { + return + } + rawIdChange = &treechangeproto.RawTreeChangeWithId{ + RawChange: marshalledRawChange, + Id: id, + } + + return +} + +func rawAclWithId(accountKeys *accountdata.AccountKeys, spaceId string) (aclHeadId string, rawWithId *aclrecordproto.RawAclRecordWithId, err error) { + readKeyBytes := make([]byte, 32) + _, err = rand.Read(readKeyBytes) + if err != nil { + return + } + readKey, err := accountKeys.SignKey.GetPublic().Encrypt(readKeyBytes) + if err != nil { + return + } + masterKey, _, err := crypto.GenerateRandomEd25519KeyPair() + identity, err := accountKeys.SignKey.GetPublic().Marshall() + if err != nil { + return + } + masterPubKey := masterKey.GetPublic() + rawIdentity, err := accountKeys.SignKey.GetPublic().Raw() + if err != nil { + return + } + identitySignature, err := masterKey.Sign(rawIdentity) + if err != nil { + return + } + rawMasterKey, err := masterPubKey.Marshall() + if err != nil { + return + } + aclRoot := aclrecordproto.AclRoot{ + Identity: identity, + MasterKey: rawMasterKey, + SpaceId: spaceId, + EncryptedReadKey: readKey, + Timestamp: time.Now().Unix(), + IdentitySignature: identitySignature, + } + marshalled, err := aclRoot.Marshal() + if err != nil { + return + } + signature, err := accountKeys.SignKey.Sign(marshalled) + rawAclRecord := &aclrecordproto.RawAclRecord{ + Payload: marshalled, + Signature: signature, + } + marshalledRaw, err := rawAclRecord.Marshal() + if err != nil { + return + } + aclHeadId, err = cidutil.NewCidFromBytes(marshalledRaw) + if err != nil { + return + } + rawWithId = &aclrecordproto.RawAclRecordWithId{ + Payload: marshalledRaw, + Id: aclHeadId, + } + + return +} + +func rawHeaderWithId(accountKeys *accountdata.AccountKeys) (spaceId string, rawWithId *spacesyncproto.RawSpaceHeaderWithId, err error) { + identity, err := accountKeys.SignKey.GetPublic().Marshall() + if err != nil { + return + } + spaceHeaderSeed := make([]byte, 32) + _, err = rand.Read(spaceHeaderSeed) + if err != nil { + return + } + spaceHeaderPayload := make([]byte, 32) + _, err = rand.Read(spaceHeaderPayload) + if err != nil { + return + } + replicationKey := rand.Uint64() + header := &spacesyncproto.SpaceHeader{ + Identity: identity, + Timestamp: time.Now().Unix(), + SpaceType: "SpaceType", + ReplicationKey: replicationKey, + Seed: spaceHeaderSeed, + SpaceHeaderPayload: spaceHeaderPayload, + } + marhalled, err := header.Marshal() + if err != nil { + return + } + signature, err := accountKeys.SignKey.Sign(marhalled) + if err != nil { + return + } + rawHeader := &spacesyncproto.RawSpaceHeader{ + SpaceHeader: marhalled, + Signature: signature, + } + marhalledRawHeader, err := rawHeader.Marshal() + if err != nil { + return + } + id, err := cidutil.NewCidFromBytes(marhalledRawHeader) + if err != nil { + return + } + spaceId = fmt.Sprintf("%s.%s", id, strconv.FormatUint(replicationKey, 36)) + rawWithId = &spacesyncproto.RawSpaceHeaderWithId{ + RawHeader: marhalledRawHeader, + Id: spaceId, + } + + return +} diff --git a/commonspace/spaceservice.go b/commonspace/spaceservice.go index 31a8331b..4aafb0a2 100644 --- a/commonspace/spaceservice.go +++ b/commonspace/spaceservice.go @@ -80,7 +80,7 @@ func (s *spaceService) CreateSpace(ctx context.Context, payload SpaceCreatePaylo if err != nil { return } - store, err := s.storageProvider.CreateSpaceStorage(storageCreate) + store, err := s.createSpaceStorage(storageCreate) if err != nil { if err == spacestorage.ErrSpaceStorageExists { return storageCreate.SpaceHeaderWithId.Id, nil @@ -105,7 +105,7 @@ func (s *spaceService) DeriveSpace(ctx context.Context, payload SpaceDerivePaylo if err != nil { return } - store, err := s.storageProvider.CreateSpaceStorage(storageCreate) + store, err := s.createSpaceStorage(storageCreate) if err != nil { if err == spacestorage.ErrSpaceStorageExists { return storageCreate.SpaceHeaderWithId.Id, nil @@ -197,7 +197,7 @@ func (s *spaceService) addSpaceStorage(ctx context.Context, spaceDescription Spa Id: spaceDescription.SpaceSettingsId, }, } - st, err = s.storageProvider.CreateSpaceStorage(payload) + st, err = s.createSpaceStorage(payload) if err != nil { err = spacesyncproto.ErrUnexpected if err == spacestorage.ErrSpaceStorageExists { @@ -229,7 +229,7 @@ func (s *spaceService) getSpaceStorageFromRemote(ctx context.Context, id string) return } - st, err = s.storageProvider.CreateSpaceStorage(spacestorage.SpaceStorageCreatePayload{ + st, err = s.createSpaceStorage(spacestorage.SpaceStorageCreatePayload{ AclWithId: &aclrecordproto.RawAclRecordWithId{ Payload: res.Payload.AclPayload, Id: res.Payload.AclPayloadId, @@ -242,3 +242,11 @@ func (s *spaceService) getSpaceStorageFromRemote(ctx context.Context, id string) }) return } + +func (s *spaceService) createSpaceStorage(payload spacestorage.SpaceStorageCreatePayload) (spacestorage.SpaceStorage, error) { + err := validateSpaceStorageCreatePayload(payload) + if err != nil { + return nil, err + } + return s.storageProvider.CreateSpaceStorage(payload) +} diff --git a/commonspace/spacestorage/spacestorage.go b/commonspace/spacestorage/spacestorage.go index 3f21c22e..25991922 100644 --- a/commonspace/spacestorage/spacestorage.go +++ b/commonspace/spacestorage/spacestorage.go @@ -4,19 +4,12 @@ package spacestorage import ( "context" "errors" - "fmt" "github.com/anytypeio/any-sync/app" "github.com/anytypeio/any-sync/commonspace/object/acl/aclrecordproto" "github.com/anytypeio/any-sync/commonspace/object/acl/liststorage" - "github.com/anytypeio/any-sync/commonspace/object/tree/objecttree" "github.com/anytypeio/any-sync/commonspace/object/tree/treechangeproto" "github.com/anytypeio/any-sync/commonspace/object/tree/treestorage" "github.com/anytypeio/any-sync/commonspace/spacesyncproto" - "github.com/anytypeio/any-sync/util/cidutil" - "github.com/anytypeio/any-sync/util/crypto" - "github.com/gogo/protobuf/proto" - "strconv" - "strings" ) const CName = "common.commonspace.spacestorage" @@ -67,177 +60,3 @@ type SpaceStorageProvider interface { SpaceExists(id string) bool CreateSpaceStorage(payload SpaceStorageCreatePayload) (SpaceStorage, error) } - -func ValidateSpaceStorageCreatePayload(payload SpaceStorageCreatePayload) (err error) { - err = validateCreateSpaceHeaderPayload(payload.SpaceHeaderWithId) - if err != nil { - return - } - aclSpaceId, err := validateCreateSpaceAclPayload(payload.AclWithId) - if err != nil { - return - } - aclHeadId, settingsSpaceId, err := validateCreateSpaceSettingsPayload(payload.SpaceSettingsWithId) - if err != nil { - return - } - if aclSpaceId != payload.SpaceHeaderWithId.Id || aclSpaceId != settingsSpaceId { - err = ErrIncorrectSpaceHeader - return - } - if aclHeadId != payload.AclWithId.Id { - err = ErrIncorrectSpaceHeader - return - } - return -} - -func validateCreateSpaceHeaderPayload(rawHeaderWithId *spacesyncproto.RawSpaceHeaderWithId) (err error) { - var rawSpaceHeader spacesyncproto.RawSpaceHeader - err = proto.Unmarshal(rawHeaderWithId.RawHeader, &rawSpaceHeader) - if err != nil { - return - } - var header spacesyncproto.SpaceHeader - err = proto.Unmarshal(rawSpaceHeader.SpaceHeader, &header) - if err != nil { - return - } - split := strings.Split(rawHeaderWithId.Id, ".") - if len(split) != 2 { - return ErrIncorrectSpaceHeader - } - if !cidutil.VerifyCid(rawHeaderWithId.RawHeader, split[0]) { - err = objecttree.ErrIncorrectCid - return - } - payloadIdentity, err := crypto.UnmarshalEd25519PublicKeyProto(header.Identity) - if err != nil { - return - } - res, err := payloadIdentity.Verify(rawSpaceHeader.SpaceHeader, rawSpaceHeader.Signature) - if err != nil || !res { - err = ErrIncorrectSpaceHeader - return - } - id, err := cidutil.NewCidFromBytes(rawHeaderWithId.RawHeader) - if err != nil { - return - } - requiredSpaceId := fmt.Sprintf("%s.%s", id, strconv.FormatUint(header.ReplicationKey, 36)) - if requiredSpaceId != rawHeaderWithId.Id { - err = ErrIncorrectSpaceHeader - return - } - - return -} - -func validateCreateSpaceAclPayload(rawWithId *aclrecordproto.RawAclRecordWithId) (spaceId string, err error) { - if !cidutil.VerifyCid(rawWithId.Payload, rawWithId.Id) { - err = objecttree.ErrIncorrectCid - return - } - var rawAcl aclrecordproto.RawAclRecord - err = proto.Unmarshal(rawWithId.Payload, &rawAcl) - if err != nil { - return - } - var aclRoot aclrecordproto.AclRoot - err = proto.Unmarshal(rawAcl.Payload, &aclRoot) - if err != nil { - return - } - payloadIdentity, err := crypto.UnmarshalEd25519PublicKeyProto(aclRoot.Identity) - if err != nil { - return - } - res, err := payloadIdentity.Verify(rawAcl.Payload, rawAcl.Signature) - if err != nil || !res { - err = ErrIncorrectSpaceHeader - return - } - masterKey, err := crypto.UnmarshalEd25519PublicKeyProto(aclRoot.MasterKey) - if err != nil { - return - } - rawIdentity, err := payloadIdentity.Raw() - if err != nil { - return - } - res, err = masterKey.Verify(rawIdentity, aclRoot.IdentitySignature) - if err != nil || !res { - err = ErrIncorrectSpaceHeader - return - } - spaceId = aclRoot.SpaceId - - return -} - -func validateCreateSpaceSettingsPayload(rawWithId *treechangeproto.RawTreeChangeWithId) (aclHeadId string, spaceId string, err error) { - var raw treechangeproto.RawTreeChange - err = proto.Unmarshal(rawWithId.RawChange, &raw) - if err != nil { - return - } - var rootChange treechangeproto.RootChange - err = proto.Unmarshal(raw.Payload, &rootChange) - if err != nil { - return - } - payloadIdentity, err := crypto.UnmarshalEd25519PublicKeyProto(rootChange.Identity) - if err != nil { - return - } - res, err := payloadIdentity.Verify(raw.Payload, raw.Signature) - if err != nil || !res { - err = ErrIncorrectSpaceHeader - return - } - id, err := cidutil.NewCidFromBytes(rawWithId.RawChange) - if id != rawWithId.Id { - err = ErrIncorrectSpaceHeader - return - } - spaceId = rootChange.SpaceId - aclHeadId = rootChange.AclHeadId - - return -} - -// ValidateSpaceHeader Used in coordinator -func ValidateSpaceHeader(spaceId string, header []byte, identity crypto.PubKey) (err error) { - split := strings.Split(spaceId, ".") - if len(split) != 2 { - return ErrIncorrectSpaceHeader - } - if !cidutil.VerifyCid(header, split[0]) { - err = objecttree.ErrIncorrectCid - return - } - raw := &spacesyncproto.RawSpaceHeader{} - err = proto.Unmarshal(header, raw) - if err != nil { - return - } - payload := &spacesyncproto.SpaceHeader{} - err = proto.Unmarshal(raw.SpaceHeader, payload) - if err != nil { - return - } - payloadIdentity, err := crypto.UnmarshalEd25519PublicKeyProto(payload.Identity) - if err != nil { - return - } - if identity != nil && !payloadIdentity.Equals(identity) { - err = ErrIncorrectSpaceHeader - return - } - res, err := identity.Verify(raw.SpaceHeader, raw.Signature) - if err != nil || !res { - err = ErrIncorrectSpaceHeader - return - } - return -} diff --git a/commonspace/spacestorage/spacestorage_test.go b/commonspace/spacestorage/spacestorage_test.go index 8243291e..82a25c1d 100644 --- a/commonspace/spacestorage/spacestorage_test.go +++ b/commonspace/spacestorage/spacestorage_test.go @@ -1,655 +1,2 @@ package spacestorage -import ( - "crypto/rand" - "fmt" - "github.com/anytypeio/any-sync/commonspace/object/accountdata" - "github.com/anytypeio/any-sync/commonspace/object/acl/aclrecordproto" - "github.com/anytypeio/any-sync/commonspace/object/tree/objecttree" - "github.com/anytypeio/any-sync/commonspace/object/tree/treechangeproto" - "github.com/anytypeio/any-sync/commonspace/spacesyncproto" - "github.com/anytypeio/any-sync/util/cidutil" - "github.com/anytypeio/any-sync/util/crypto" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - rand2 "golang.org/x/exp/rand" - "strconv" - "testing" - "time" -) - -func TestSuccessHeaderPayloadForSpaceCreate(t *testing.T) { - accountKeys, err := accountdata.NewRandom() - require.NoError(t, err) - _, rawHeaderWithId, err := rawHeaderWithId(accountKeys) - require.NoError(t, err) - err = validateCreateSpaceHeaderPayload(rawHeaderWithId) - require.NoError(t, err) -} - -func TestFailedHeaderPayloadForSpaceCreate_InvalidFormatSpaceId(t *testing.T) { - accountKeys, err := accountdata.NewRandom() - require.NoError(t, err) - identity, err := accountKeys.SignKey.GetPublic().Marshall() - require.NoError(t, err) - spaceHeaderSeed := make([]byte, 32) - _, err = rand.Read(spaceHeaderSeed) - require.NoError(t, err) - spaceHeaderPayload := make([]byte, 32) - _, err = rand.Read(spaceHeaderPayload) - require.NoError(t, err) - replicationKey := rand2.Uint64() - header := &spacesyncproto.SpaceHeader{ - Identity: identity, - Timestamp: time.Now().Unix(), - SpaceType: "SpaceType", - ReplicationKey: replicationKey, - Seed: spaceHeaderSeed, - SpaceHeaderPayload: spaceHeaderPayload, - } - marhalled, err := header.Marshal() - require.NoError(t, err) - signature, err := accountKeys.SignKey.Sign(marhalled) - require.NoError(t, err) - rawHeader := &spacesyncproto.RawSpaceHeader{ - SpaceHeader: marhalled, - Signature: signature, - } - marhalledRawHeader, err := rawHeader.Marshal() - require.NoError(t, err) - id, err := cidutil.NewCidFromBytes(marhalled) - require.NoError(t, err) - spaceId := fmt.Sprintf("%s%s", id, strconv.FormatUint(replicationKey, 36)) - rawHeaderWithId := &spacesyncproto.RawSpaceHeaderWithId{ - RawHeader: marhalledRawHeader, - Id: spaceId, - } - err = validateCreateSpaceHeaderPayload(rawHeaderWithId) - assert.EqualErrorf(t, err, ErrIncorrectSpaceHeader.Error(), "Error should be: %v, got: %v", ErrIncorrectSpaceHeader, err) -} - -func TestFailedHeaderPayloadForSpaceCreate_CidIsWrong(t *testing.T) { - accountKeys, err := accountdata.NewRandom() - require.NoError(t, err) - identity, err := accountKeys.SignKey.GetPublic().Marshall() - require.NoError(t, err) - spaceHeaderSeed := make([]byte, 32) - _, err = rand.Read(spaceHeaderSeed) - require.NoError(t, err) - spaceHeaderPayload := make([]byte, 32) - _, err = rand.Read(spaceHeaderPayload) - require.NoError(t, err) - replicationKey := rand2.Uint64() - header := &spacesyncproto.SpaceHeader{ - Identity: identity, - Timestamp: time.Now().Unix(), - SpaceType: "SpaceType", - ReplicationKey: replicationKey, - Seed: spaceHeaderSeed, - SpaceHeaderPayload: spaceHeaderPayload, - } - marhalled, err := header.Marshal() - require.NoError(t, err) - signature, err := accountKeys.SignKey.Sign(marhalled) - require.NoError(t, err) - rawHeader := &spacesyncproto.RawSpaceHeader{ - SpaceHeader: marhalled, - Signature: signature, - } - marhalledRawHeader, err := rawHeader.Marshal() - require.NoError(t, err) - id := "faisdfjpiocpoakopkop34" - spaceId := fmt.Sprintf("%s.%s", id, strconv.FormatUint(replicationKey, 36)) - rawHeaderWithId := &spacesyncproto.RawSpaceHeaderWithId{ - RawHeader: marhalledRawHeader, - Id: spaceId, - } - err = validateCreateSpaceHeaderPayload(rawHeaderWithId) - assert.EqualErrorf(t, err, objecttree.ErrIncorrectCid.Error(), "Error should be: %v, got: %v", objecttree.ErrIncorrectCid, err) -} - -func TestFailedHeaderPayloadForSpaceCreate_SignedWithAnotherIdentity(t *testing.T) { - accountKeys, err := accountdata.NewRandom() - require.NoError(t, err) - identity, err := accountKeys.SignKey.GetPublic().Marshall() - require.NoError(t, err) - spaceHeaderSeed := make([]byte, 32) - _, err = rand.Read(spaceHeaderSeed) - require.NoError(t, err) - spaceHeaderPayload := make([]byte, 32) - _, err = rand.Read(spaceHeaderPayload) - require.NoError(t, err) - replicationKey := rand2.Uint64() - header := &spacesyncproto.SpaceHeader{ - Identity: identity, - Timestamp: time.Now().Unix(), - SpaceType: "SpaceType", - ReplicationKey: replicationKey, - Seed: spaceHeaderSeed, - SpaceHeaderPayload: spaceHeaderPayload, - } - marhalled, err := header.Marshal() - require.NoError(t, err) - anotherAccountKeys, err := accountdata.NewRandom() - signature, err := anotherAccountKeys.SignKey.Sign(marhalled) - require.NoError(t, err) - rawHeader := &spacesyncproto.RawSpaceHeader{ - SpaceHeader: marhalled, - Signature: signature, - } - marhalledRawHeader, err := rawHeader.Marshal() - require.NoError(t, err) - id := "faisdfjpiocpoakopkop34" - spaceId := fmt.Sprintf("%s.%s", id, strconv.FormatUint(replicationKey, 36)) - rawHeaderWithId := &spacesyncproto.RawSpaceHeaderWithId{ - RawHeader: marhalledRawHeader, - Id: spaceId, - } - err = validateCreateSpaceHeaderPayload(rawHeaderWithId) - assert.EqualErrorf(t, err, objecttree.ErrIncorrectCid.Error(), "Error should be: %v, got: %v", objecttree.ErrIncorrectCid, err) -} - -func TestSuccessAclPayloadSpace(t *testing.T) { - accountKeys, err := accountdata.NewRandom() - spaceId := "AnySpaceId" - _, rawWithId, err := rawAclWithId(accountKeys, spaceId) - require.NoError(t, err) - validationSpaceId, err := validateCreateSpaceAclPayload(rawWithId) - require.Equal(t, validationSpaceId, spaceId) - require.NoError(t, err) -} - -func TestFailAclPayloadSpace_IncorrectCid(t *testing.T) { - accountKeys, err := accountdata.NewRandom() - require.NoError(t, err) - identity, err := accountKeys.SignKey.GetPublic().Marshall() - require.NoError(t, err) - readKeyBytes := make([]byte, 32) - _, err = rand.Read(readKeyBytes) - require.NoError(t, err) - readKey, err := accountKeys.SignKey.GetPublic().Encrypt(readKeyBytes) - require.NoError(t, err) - masterKey, _, err := crypto.GenerateRandomEd25519KeyPair() - require.NoError(t, err) - rawIdentity, err := accountKeys.SignKey.GetPublic().Raw() - require.NoError(t, err) - identitySignature, err := masterKey.Sign(rawIdentity) - require.NoError(t, err) - rawMasterKey, err := masterKey.GetPublic().Marshall() - require.NoError(t, err) - aclRoot := aclrecordproto.AclRoot{ - Identity: identity, - MasterKey: rawMasterKey, - SpaceId: "SpaceId", - EncryptedReadKey: readKey, - Timestamp: time.Now().Unix(), - IdentitySignature: identitySignature, - } - marshalled, err := aclRoot.Marshal() - require.NoError(t, err) - signature, err := accountKeys.SignKey.Sign(marshalled) - rawAclRecord := &aclrecordproto.RawAclRecord{ - Payload: marshalled, - Signature: signature, - } - marshalledRaw, err := rawAclRecord.Marshal() - require.NoError(t, err) - aclHeadId := "rand" - rawWithId := &aclrecordproto.RawAclRecordWithId{ - Payload: marshalledRaw, - Id: aclHeadId, - } - _, err = validateCreateSpaceAclPayload(rawWithId) - assert.EqualErrorf(t, err, objecttree.ErrIncorrectCid.Error(), "Error should be: %v, got: %v", objecttree.ErrIncorrectCid, err) -} - -func TestFailedAclPayloadSpace_IncorrectSignature(t *testing.T) { - accountKeys, err := accountdata.NewRandom() - require.NoError(t, err) - readKeyBytes := make([]byte, 32) - _, err = rand.Read(readKeyBytes) - require.NoError(t, err) - readKey, err := accountKeys.SignKey.GetPublic().Encrypt(readKeyBytes) - require.NoError(t, err) - masterKey, _, err := crypto.GenerateRandomEd25519KeyPair() - require.NoError(t, err) - rawIdentity, err := accountKeys.SignKey.GetPublic().Raw() - require.NoError(t, err) - identity, err := accountKeys.SignKey.GetPublic().Marshall() - identitySignature, err := masterKey.Sign(rawIdentity) - require.NoError(t, err) - rawMasterKey, err := masterKey.GetPublic().Raw() - require.NoError(t, err) - aclRoot := aclrecordproto.AclRoot{ - Identity: identity, - MasterKey: rawMasterKey, - SpaceId: "SpaceId", - EncryptedReadKey: readKey, - Timestamp: time.Now().Unix(), - IdentitySignature: identitySignature, - } - marshalled, err := aclRoot.Marshal() - require.NoError(t, err) - rawAclRecord := &aclrecordproto.RawAclRecord{ - Payload: marshalled, - Signature: marshalled, - } - marshalledRaw, err := rawAclRecord.Marshal() - require.NoError(t, err) - aclHeadId, err := cidutil.NewCidFromBytes(marshalledRaw) - require.NoError(t, err) - rawWithId := &aclrecordproto.RawAclRecordWithId{ - Payload: marshalledRaw, - Id: aclHeadId, - } - _, err = validateCreateSpaceAclPayload(rawWithId) - assert.NotNil(t, err) - assert.EqualErrorf(t, err, ErrIncorrectSpaceHeader.Error(), "Error should be: %v, got: %v", ErrIncorrectSpaceHeader, err) -} - -func TestFailedAclPayloadSpace_IncorrectIdentitySignature(t *testing.T) { - spaceId := "AnySpaceId" - accountKeys, err := accountdata.NewRandom() - require.NoError(t, err) - readKeyBytes := make([]byte, 32) - _, err = rand.Read(readKeyBytes) - if err != nil { - return - } - readKey, err := accountKeys.SignKey.GetPublic().Encrypt(readKeyBytes) - if err != nil { - return - } - masterKey, _, err := crypto.GenerateRandomEd25519KeyPair() - if err != nil { - return - } - masterPubKey := masterKey.GetPublic() - identity, err := accountKeys.SignKey.GetPublic().Marshall() - if err != nil { - return - } - rawMasterKey, err := masterPubKey.Marshall() - if err != nil { - return - } - aclRoot := aclrecordproto.AclRoot{ - Identity: identity, - MasterKey: rawMasterKey, - SpaceId: spaceId, - EncryptedReadKey: readKey, - Timestamp: time.Now().Unix(), - IdentitySignature: identity, - } - marshalled, err := aclRoot.Marshal() - if err != nil { - return - } - signature, err := accountKeys.SignKey.Sign(marshalled) - rawAclRecord := &aclrecordproto.RawAclRecord{ - Payload: marshalled, - Signature: signature, - } - marshalledRaw, err := rawAclRecord.Marshal() - if err != nil { - return - } - aclHeadId, err := cidutil.NewCidFromBytes(marshalledRaw) - if err != nil { - return - } - rawWithId := &aclrecordproto.RawAclRecordWithId{ - Payload: marshalledRaw, - Id: aclHeadId, - } - _, err = validateCreateSpaceAclPayload(rawWithId) - assert.EqualErrorf(t, err, ErrIncorrectSpaceHeader.Error(), "Error should be: %v, got: %v", ErrIncorrectSpaceHeader, err) -} - -func TestSuccessSettingsPayloadSpace(t *testing.T) { - accountKeys, err := accountdata.NewRandom() - require.NoError(t, err) - identity, err := accountKeys.SignKey.GetPublic().Marshall() - require.NoError(t, err) - spaceSettingsSeed := make([]byte, 32) - _, err = rand.Read(spaceSettingsSeed) - require.NoError(t, err) - changePayload := make([]byte, 32) - _, err = rand.Read(changePayload) - require.NoError(t, err) - spaceId := "SpaceId" - rootChange := &treechangeproto.RootChange{ - AclHeadId: "AclHeadId", - SpaceId: spaceId, - ChangeType: "ChangeType", - Timestamp: time.Now().Unix(), - Seed: spaceSettingsSeed, - Identity: identity, - ChangePayload: changePayload, - } - marshalledChange, err := rootChange.Marshal() - require.NoError(t, err) - signature, err := accountKeys.SignKey.Sign(marshalledChange) - require.NoError(t, err) - raw := &treechangeproto.RawTreeChange{ - Payload: marshalledChange, - Signature: signature, - } - marshalledRawChange, err := raw.Marshal() - id, err := cidutil.NewCidFromBytes(marshalledRawChange) - require.NoError(t, err) - rawIdChange := &treechangeproto.RawTreeChangeWithId{ - RawChange: marshalledRawChange, - Id: id, - } - _, validationSpaceId, err := validateCreateSpaceSettingsPayload(rawIdChange) - require.Equal(t, validationSpaceId, spaceId) - require.NoError(t, err) -} - -func TestFailSettingsPayloadSpace_InvalidSignature(t *testing.T) { - accountKeys, err := accountdata.NewRandom() - require.NoError(t, err) - identity, err := accountKeys.SignKey.GetPublic().Marshall() - require.NoError(t, err) - spaceSettingsSeed := make([]byte, 32) - _, err = rand.Read(spaceSettingsSeed) - require.NoError(t, err) - changePayload := make([]byte, 32) - _, err = rand.Read(changePayload) - require.NoError(t, err) - rootChange := &treechangeproto.RootChange{ - AclHeadId: "AclHeadId", - SpaceId: "SpaceId", - ChangeType: "ChangeType", - Timestamp: time.Now().Unix(), - Seed: spaceSettingsSeed, - Identity: identity, - ChangePayload: changePayload, - } - marshalledChange, err := rootChange.Marshal() - require.NoError(t, err) - raw := &treechangeproto.RawTreeChange{ - Payload: marshalledChange, - Signature: marshalledChange, - } - marshalledRawChange, err := raw.Marshal() - id, err := cidutil.NewCidFromBytes(marshalledRawChange) - require.NoError(t, err) - rawIdChange := &treechangeproto.RawTreeChangeWithId{ - RawChange: marshalledRawChange, - Id: id, - } - _, _, err = validateCreateSpaceSettingsPayload(rawIdChange) - assert.EqualErrorf(t, err, ErrIncorrectSpaceHeader.Error(), "Error should be: %v, got: %v", ErrIncorrectSpaceHeader, err) -} - -func TestFailSettingsPayloadSpace_InvalidCid(t *testing.T) { - accountKeys, err := accountdata.NewRandom() - require.NoError(t, err) - identity, err := accountKeys.SignKey.GetPublic().Marshall() - require.NoError(t, err) - spaceSettingsSeed := make([]byte, 32) - _, err = rand.Read(spaceSettingsSeed) - require.NoError(t, err) - changePayload := make([]byte, 32) - _, err = rand.Read(changePayload) - require.NoError(t, err) - rootChange := &treechangeproto.RootChange{ - AclHeadId: "AclHeadId", - SpaceId: "SpaceId", - ChangeType: "ChangeType", - Timestamp: time.Now().Unix(), - Seed: spaceSettingsSeed, - Identity: identity, - ChangePayload: changePayload, - } - marshalledChange, err := rootChange.Marshal() - require.NoError(t, err) - signature, err := accountKeys.SignKey.Sign(marshalledChange) - require.NoError(t, err) - raw := &treechangeproto.RawTreeChange{ - Payload: marshalledChange, - Signature: signature, - } - marshalledRawChange, err := raw.Marshal() - id := "id" - require.NoError(t, err) - rawIdChange := &treechangeproto.RawTreeChangeWithId{ - RawChange: marshalledRawChange, - Id: id, - } - _, _, err = validateCreateSpaceSettingsPayload(rawIdChange) - assert.EqualErrorf(t, err, ErrIncorrectSpaceHeader.Error(), "Error should be: %v, got: %v", ErrIncorrectSpaceHeader, err) -} - -func TestSuccessSameIds(t *testing.T) { - accountKeys, err := accountdata.NewRandom() - require.NoError(t, err) - spaceId, rawHeaderWithId, err := rawHeaderWithId(accountKeys) - require.NoError(t, err) - aclHeadId, rawAclWithId, err := rawAclWithId(accountKeys, spaceId) - require.NoError(t, err) - rawSettingsPayload, err := rawSettingsPayload(accountKeys, spaceId, aclHeadId) - spacePayload := SpaceStorageCreatePayload{ - AclWithId: rawAclWithId, - SpaceHeaderWithId: rawHeaderWithId, - SpaceSettingsWithId: rawSettingsPayload, - } - err = ValidateSpaceStorageCreatePayload(spacePayload) - require.NoError(t, err) -} - -func TestFailWithAclWrongSpaceId(t *testing.T) { - accountKeys, err := accountdata.NewRandom() - require.NoError(t, err) - spaceId, rawHeaderWithId, err := rawHeaderWithId(accountKeys) - require.NoError(t, err) - aclHeadId, rawAclWithId, err := rawAclWithId(accountKeys, "spaceId") - require.NoError(t, err) - rawSettingsPayload, err := rawSettingsPayload(accountKeys, spaceId, aclHeadId) - spacePayload := SpaceStorageCreatePayload{ - AclWithId: rawAclWithId, - SpaceHeaderWithId: rawHeaderWithId, - SpaceSettingsWithId: rawSettingsPayload, - } - err = ValidateSpaceStorageCreatePayload(spacePayload) - assert.EqualErrorf(t, err, ErrIncorrectSpaceHeader.Error(), "Error should be: %v, got: %v", ErrIncorrectSpaceHeader, err) -} - -func TestFailWithSettingsWrongSpaceId(t *testing.T) { - accountKeys, err := accountdata.NewRandom() - require.NoError(t, err) - spaceId, rawHeaderWithId, err := rawHeaderWithId(accountKeys) - require.NoError(t, err) - aclHeadId, rawAclWithId, err := rawAclWithId(accountKeys, spaceId) - require.NoError(t, err) - rawSettingsPayload, err := rawSettingsPayload(accountKeys, "spaceId", aclHeadId) - spacePayload := SpaceStorageCreatePayload{ - AclWithId: rawAclWithId, - SpaceHeaderWithId: rawHeaderWithId, - SpaceSettingsWithId: rawSettingsPayload, - } - err = ValidateSpaceStorageCreatePayload(spacePayload) - assert.EqualErrorf(t, err, ErrIncorrectSpaceHeader.Error(), "Error should be: %v, got: %v", ErrIncorrectSpaceHeader, err) -} - -func TestFailWithWrongAclHeadIdInSettingsPayload(t *testing.T) { - accountKeys, err := accountdata.NewRandom() - require.NoError(t, err) - spaceId, rawHeaderWithId, err := rawHeaderWithId(accountKeys) - require.NoError(t, err) - _, rawAclWithId, err := rawAclWithId(accountKeys, spaceId) - require.NoError(t, err) - rawSettingsPayload, err := rawSettingsPayload(accountKeys, spaceId, "aclHeadId") - spacePayload := SpaceStorageCreatePayload{ - AclWithId: rawAclWithId, - SpaceHeaderWithId: rawHeaderWithId, - SpaceSettingsWithId: rawSettingsPayload, - } - err = ValidateSpaceStorageCreatePayload(spacePayload) - assert.EqualErrorf(t, err, ErrIncorrectSpaceHeader.Error(), "Error should be: %v, got: %v", ErrIncorrectSpaceHeader, err) -} - -func rawSettingsPayload(accountKeys *accountdata.AccountKeys, spaceId, aclHeadId string) (rawIdChange *treechangeproto.RawTreeChangeWithId, err error) { - identity, err := accountKeys.SignKey.GetPublic().Marshall() - if err != nil { - return - } - spaceSettingsSeed := make([]byte, 32) - _, err = rand.Read(spaceSettingsSeed) - if err != nil { - return - } - changePayload := make([]byte, 32) - _, err = rand.Read(changePayload) - if err != nil { - return - } - rootChange := &treechangeproto.RootChange{ - AclHeadId: aclHeadId, - SpaceId: spaceId, - ChangeType: "ChangeType", - Timestamp: time.Now().Unix(), - Seed: spaceSettingsSeed, - Identity: identity, - ChangePayload: changePayload, - } - marshalledChange, err := rootChange.Marshal() - if err != nil { - return - } - signature, err := accountKeys.SignKey.Sign(marshalledChange) - if err != nil { - return - } - raw := &treechangeproto.RawTreeChange{ - Payload: marshalledChange, - Signature: signature, - } - marshalledRawChange, err := raw.Marshal() - id, err := cidutil.NewCidFromBytes(marshalledRawChange) - if err != nil { - return - } - rawIdChange = &treechangeproto.RawTreeChangeWithId{ - RawChange: marshalledRawChange, - Id: id, - } - - return -} - -func rawAclWithId(accountKeys *accountdata.AccountKeys, spaceId string) (aclHeadId string, rawWithId *aclrecordproto.RawAclRecordWithId, err error) { - readKeyBytes := make([]byte, 32) - _, err = rand.Read(readKeyBytes) - if err != nil { - return - } - readKey, err := accountKeys.SignKey.GetPublic().Encrypt(readKeyBytes) - if err != nil { - return - } - masterKey, _, err := crypto.GenerateRandomEd25519KeyPair() - identity, err := accountKeys.SignKey.GetPublic().Marshall() - if err != nil { - return - } - masterPubKey := masterKey.GetPublic() - rawIdentity, err := accountKeys.SignKey.GetPublic().Raw() - if err != nil { - return - } - identitySignature, err := masterKey.Sign(rawIdentity) - if err != nil { - return - } - rawMasterKey, err := masterPubKey.Marshall() - if err != nil { - return - } - aclRoot := aclrecordproto.AclRoot{ - Identity: identity, - MasterKey: rawMasterKey, - SpaceId: spaceId, - EncryptedReadKey: readKey, - Timestamp: time.Now().Unix(), - IdentitySignature: identitySignature, - } - marshalled, err := aclRoot.Marshal() - if err != nil { - return - } - signature, err := accountKeys.SignKey.Sign(marshalled) - rawAclRecord := &aclrecordproto.RawAclRecord{ - Payload: marshalled, - Signature: signature, - } - marshalledRaw, err := rawAclRecord.Marshal() - if err != nil { - return - } - aclHeadId, err = cidutil.NewCidFromBytes(marshalledRaw) - if err != nil { - return - } - rawWithId = &aclrecordproto.RawAclRecordWithId{ - Payload: marshalledRaw, - Id: aclHeadId, - } - - return -} - -func rawHeaderWithId(accountKeys *accountdata.AccountKeys) (spaceId string, rawWithId *spacesyncproto.RawSpaceHeaderWithId, err error) { - identity, err := accountKeys.SignKey.GetPublic().Marshall() - if err != nil { - return - } - spaceHeaderSeed := make([]byte, 32) - _, err = rand.Read(spaceHeaderSeed) - if err != nil { - return - } - spaceHeaderPayload := make([]byte, 32) - _, err = rand.Read(spaceHeaderPayload) - if err != nil { - return - } - replicationKey := rand2.Uint64() - header := &spacesyncproto.SpaceHeader{ - Identity: identity, - Timestamp: time.Now().Unix(), - SpaceType: "SpaceType", - ReplicationKey: replicationKey, - Seed: spaceHeaderSeed, - SpaceHeaderPayload: spaceHeaderPayload, - } - marhalled, err := header.Marshal() - if err != nil { - return - } - signature, err := accountKeys.SignKey.Sign(marhalled) - if err != nil { - return - } - rawHeader := &spacesyncproto.RawSpaceHeader{ - SpaceHeader: marhalled, - Signature: signature, - } - marhalledRawHeader, err := rawHeader.Marshal() - if err != nil { - return - } - id, err := cidutil.NewCidFromBytes(marhalledRawHeader) - if err != nil { - return - } - spaceId = fmt.Sprintf("%s.%s", id, strconv.FormatUint(replicationKey, 36)) - rawWithId = &spacesyncproto.RawSpaceHeaderWithId{ - RawHeader: marhalledRawHeader, - Id: spaceId, - } - - return -}