diff --git a/etc/acl.yml b/etc/acl.yml new file mode 100644 index 00000000..85bcfacc --- /dev/null +++ b/etc/acl.yml @@ -0,0 +1,28 @@ +records: + - identity: A + aclChanges: + - userAdd: + identity: A + permission: admin + encryptionKey: key.Enc.A + encryptedReadKeys: [key.Read.1] + - userAdd: + identity: B + permission: admin + encryptionKey: key.Enc.B + encryptedReadKeys: [key.Read.1] + readKey: key.Read.1 +keys: + Enc: + - name: A + value: JgG4CcCbae1qEpe7mKpBzsHjZhXUmDSNVNX2B1gxFZsJyMX4V6kBQUott9zRWyeXaW1ZmpzuxDXnwSQpAnNurhXyGa9iQaAPqzY9A9VWBPD33Yy1eW7TRuVemzToh8jJQKQKnZNbF8ucTWV9qahusKzyvN8uyhrqoW2tAPfA9S3E3ognCuqbLSW6yjE2rBKayvyS1BVwzjSd6FZK4DDyjfU3pbEVjut3wytGEAn9af6sNMmyCnf2MX5vLovWs9rU8av61wD4z7HTsXyGFx4K75N4Go249Hpe9SKAT6HxhRc3yvj63krPLiQV5yMuH2UeMUXBDekUQyNmBEdn9wrur7mLqB67Bc6tcc2PP8XApBCdWJHvHjN4FktSpaG5vbCqoZbLD1oCbk36q2x9s6XM8pydVqD1J9P3nTbfgMb5pJCTFjNtgKeuKv6wjfJeA9jF1VhcJQisfsahgv9MvZ9M8FJpZTq1zKUhYDCRnZxUkraoMS5yNNVdDzaUckKEDthqik7BMWCWT79vq7uVgMwEvGwGi76gtoMg1159bbPMLZ4bdPVfhH2S9QjPrzQfwZSrzB2YeVPjWpaXDeLDity5H8n1NK2oniAQR6gE71n81neSptsuhV6o6QpQ89AU8y57XmEsou4VEryn8vUxBHhULLxrLNUouxyWamCeFiDjk5cSN6koQsf9BYKSNTPFTrwjTKForDokMhcPdMtFktKwjv7u9UEGcY4MKvNzZZkc77gHiP8bqVtdNNoLpTFUC5SZ9i7bKdHvK12HpSy7yzzPeMXJ9UwhLxkok1g81ngTbN1yxRhvYXyHZFtguCR9kvGojDjka91MTBtk551qDw9eCn2xZT9U8jqzBCjdpvSg3mRWKMPnYAGB7m7u1ye165wyGFvzcHAx3vtXjxAqLUeKYZCjv2m6V9D2Y4qH1TQNddWqH14T1JVMis971UCH9Ddpj6a3387oUnufD1P6HZN2ieJCvptrmbGVvxJYYSvmVf1dkwbtqurDRNWD7TJ7gf6iqSP549C9bxP4GpLt3ygjHmMtcuUzstBuztvunJUnQhfnJxqU6LjRdsFzm53wGWgXNxab7ZvQcPyLwsevn1b98FGPnVpS5iY4LjmqW4ugrC6HgrbsjrXiKzR1yZKhLQkCbLzPoaHb8iB5iBnCr7d4yf5CtfpFRqgoqMFdK5LNZYmDX4HzUKN6A7wC3gGiSRFTLcgGZeSMkB5Pa61CZBU7WCQgFxykycE9HRA7PiQa496GWDCV15teToCpFRsAa6jDmR1MGXPeLRqQgve49VXnQN5FL7c1VuEv5SWjeTuCnMB47DJKBaP7eKJNKgLwETALzSCMF3nRiRgeb15kfoS4BbrJ5yupjrvwmbmvNg1AYFFS5sYNWft7K8v87wQvBakRtGP71Kp8NX77XFtu6xdB7sR6jpfC6qJPyB9akWNXgCrWy9kE4ih42gwAZdUugNZ9YtEsgRM3pwb6qJhkAPyEJtrxrja859PCAgqPSQiPQN33PaMkgQ6HJknu8CrjKRiXAycZ16KLUkHV64TNhEjPTcX1a7rqpD131AYMWX8d7CCdc9Ys7RUb6BwguuNSh8rJK3x4AkMDSUsaE8ynKvpC7RXZpJ9Nxfhd + - name: B + value: JgG4CcCbae1qEpe7mKXzp7m5hNc56SSyZd9DwUaEStKJrq7RToAC2Vgd3i6hKRwa58zCWeN6Wjc3o6qrdKPEPRvcyEPysamajVo5mdQiUgWAmr97pGEsyjuRjQoC2GY2LvLiEQxEgwFgJxKGMHMiaWMtDfxCDUaDEm4bu5RdMhqRZekAWho6c3WoEeruSr14iX1TrocFNfBkBY7CjEw8kcywXCTNgtvhb2Qiwgj5AxEF4wyw4bzaNA9ctXb1hoHPFVMu6C51pkFY7jUD9zwyH3ukgnAewkGAcPNbKmaTAtMosKRVaAN97mAwXh2VRt1hWmRvVk7r76EjnVKhD4vbsKZc56RVcHTVWRVdhU7FGyPsiE5rSQAz1JQGYzxnZpX7EG77CyrmUGyfueVfRHhwY2oq8A4uQCRaQxSaJHYLowjXSxh8DQ2V6MTqyzti32C27utBYdHzLVCJSGkmdzGwrFcHqsq7nLDxmvJVErPvyReixEe8kFmqopJ3e6LLm8WdYw9K6JYBjXnEfwPzm7Von9sf3dcaGDUHYfttMyeke7fAXJkvPRje69hYVyzdQGAauuojzGkkvQWCSMK1KCMNMznRaPDCNvofrQhYrub24WhmwpKhorufdfW8Cb4T6reBDCtaWVsbuinjtL6F6Sui5aYHJFLJ6e4pPewr1P4EuZYRbMBZwN5KvDLhTGLBuBnaTqUUdF6bj2U22NoRYMogiHiftqKqiexKNDXX1Zg9RQEvxgjuVo6SBW42mVEA8agrLhruRqCmiduJxVrfqLNGeYXHXrcmMEgW7uosJbPXvTcfRvdFWS1ov7oSALvj6vhDQ28Yi9D2ETNdNsfVWAFQuwvPpW7CHQGXTitprVbqH8JYxNZuGygcLmr5efbB22Vzu4ntd1HoraQpG12qeDEUA7tXYUpoYyuSdWwKPjSAMtaQcCSfVrhKQHQuKJargrVrez8vjWuwLfvSucV7ZHe7gjqvYgULdE1ubRCRSd7DuLjEN2Vd6obzV2c3MRet7ZSf4Sp88WM5AuTyW7BjArBc4S3gUQ8rYaiZ8Tu7NCxkEzbFwWRaemZkwfvcsX3XxqjyF37tFSGkEqE5kuBvpZW72675LkDffj7kH1zA8yE6dVujJjWsNYVFJWndUtz5Vy2KCdZAbBgq19q4AtsxWPodU2N3yZXzFAFAzTrxS6V4P7Scpdau1avgRvHLcBQPunA37xaYMy8YMifJwtmRY25mnAQwZAk3eANk7tXwZd58SDnciLNvARJvwKzTQBXcshkwyy52SX8XmXDJsPnRLaHmiYBJ63Yzr5XpZuuAtxb9qrWG2NHCNxfomHokWacV1hjZPPd6ZxT1FuRozB6Qt2NLcyqY7bnTcQJb1jPUaTAGXXCR8WVmmmYo2fDQe8CdBmgyPvbzNTEJUyScBz4RdycB5PZap4SurJCWtHbuMyQbQUB6jJgURDstfXS5Akfe4oruNq9rnYcNtnsDJPtrhXHBqzDizmf1BDxR5FB2RCxzCgeAfg8WQ1Ug9PVAGTzob6ZqCrGXzWXEUniZnf1vjr7QhGKBYXEX9SWDoSMUpP4FreVDTnx15ijRZTV3p8xG5fE9e36TnugRVvTyq7XzmyPBjW2r66f1bior + Sign: + - name: A + value: 3id6ddLcoNoe9rDgGM88ET8T6TnvHm5GFqFdN6kBzn7Q8d6VUGgjeT59CNWFiaofdeRnHBvX2A5ZacMXvfwaYEFuCbug + - name: B + value: 3iiLPj6wMUQpPwTBNZcUgkbXub1jumg4AEV9LfMyFHZVc84GLyAjVbVvH6EAGhcNrxRxL82aW4BimhDZCpLsRCqx5vwj + Read: + - name: 1 + value: generated diff --git a/etc/path.go b/etc/path.go new file mode 100644 index 00000000..a90b9125 --- /dev/null +++ b/etc/path.go @@ -0,0 +1,15 @@ +package etc + +import ( + "path/filepath" + "runtime" +) + +var ( + _, b, _, _ = runtime.Caller(0) + basepath = filepath.Dir(b) +) + +func Path() string { + return basepath +} diff --git a/pkg/acl/storage/inmemory.go b/pkg/acl/storage/inmemory.go index 94e65557..651c2145 100644 --- a/pkg/acl/storage/inmemory.go +++ b/pkg/acl/storage/inmemory.go @@ -91,6 +91,17 @@ type inMemoryStorageProvider struct { sync.RWMutex } +func (i *inMemoryStorageProvider) AddStorage(id string, st Storage) error { + i.Lock() + defer i.Unlock() + if _, exists := i.objects[id]; exists { + return fmt.Errorf("storage already exists") + } + + i.objects[id] = st + return nil +} + func (i *inMemoryStorageProvider) Storage(id string) (Storage, error) { i.RLock() defer i.RUnlock() diff --git a/pkg/acl/storage/provider.go b/pkg/acl/storage/provider.go index 8dff81db..c1cf5fa9 100644 --- a/pkg/acl/storage/provider.go +++ b/pkg/acl/storage/provider.go @@ -9,5 +9,6 @@ var ErrUnknownTreeId = errors.New("tree does not exist") type Provider interface { Storage(id string) (Storage, error) + AddStorage(id string, st Storage) error CreateTreeStorage(treeId string, header *aclpb.Header, changes []*aclpb.RawChange) (TreeStorage, error) } diff --git a/pkg/acl/testutils/acllistbuilder/keychain.go b/pkg/acl/testutils/acllistbuilder/keychain.go index 7098650e..2456160b 100644 --- a/pkg/acl/testutils/acllistbuilder/keychain.go +++ b/pkg/acl/testutils/acllistbuilder/keychain.go @@ -54,11 +54,23 @@ func (k *Keychain) AddEncryptionKey(key *Key) { if _, exists := k.EncryptionKeys[key.Name]; exists { return } - newPrivKey, _, err := encryptionkey.GenerateRandomRSAKeyPair(2048) - if err != nil { - panic(err) + var ( + newPrivKey encryptionkey.PrivKey + err error + ) + if key.Value == "generated" { + newPrivKey, _, err = encryptionkey.GenerateRandomRSAKeyPair(2048) + if err != nil { + panic(err) + } + } else { + decoder := encryptionkey.NewRSAPrivKeyDecoder() + privKey, err := decoder.DecodeFromString(key.Value) + if err != nil { + panic(err) + } + newPrivKey = privKey.(encryptionkey.PrivKey) } - k.EncryptionKeys[key.Name] = newPrivKey } @@ -66,9 +78,24 @@ func (k *Keychain) AddSigningKey(key *Key) { if _, exists := k.SigningKeys[key.Name]; exists { return } - newPrivKey, pubKey, err := signingkey.GenerateRandomEd25519KeyPair() - if err != nil { - panic(err) + var ( + newPrivKey signingkey.PrivKey + pubKey signingkey.PubKey + err error + ) + if key.Value == "generated" { + newPrivKey, pubKey, err = signingkey.GenerateRandomEd25519KeyPair() + if err != nil { + panic(err) + } + } else { + decoder := signingkey.NewEDPrivKeyDecoder() + privKey, err := decoder.DecodeFromString(key.Value) + if err != nil { + panic(err) + } + newPrivKey = privKey.(signingkey.PrivKey) + pubKey = newPrivKey.GetPublic() } k.SigningKeys[key.Name] = newPrivKey diff --git a/pkg/acl/testutils/acllistbuilder/liststoragebuilder.go b/pkg/acl/testutils/acllistbuilder/liststoragebuilder.go index 25c09586..30383fc3 100644 --- a/pkg/acl/testutils/acllistbuilder/liststoragebuilder.go +++ b/pkg/acl/testutils/acllistbuilder/liststoragebuilder.go @@ -154,8 +154,7 @@ func (t *ACLListStorageBuilder) parseACLChange(ch *ACLChange) (convCh *aclpb.ACL case ch.UserAdd != nil: add := ch.UserAdd - encKey := t.keychain. - GetKey(add.EncryptionKey).(encryptionkey.PrivKey) + encKey := t.keychain.GetKey(add.EncryptionKey).(encryptionkey.PrivKey) rawKey, _ := encKey.GetPublic().Raw() convCh = &aclpb.ACLChangeACLContentValue{ diff --git a/service/document/service.go b/service/document/service.go index 369d8f1c..f6cdc097 100644 --- a/service/document/service.go +++ b/service/document/service.go @@ -58,7 +58,7 @@ func (s *service) Name() (name string) { } func (s *service) Run(ctx context.Context) (err error) { - return s.importACLList(ctx) + return nil } func (s *service) Close(ctx context.Context) (err error) { @@ -121,10 +121,6 @@ func (s *service) UpdateDocumentTree(ctx context.Context, id, text string) (err }, header, id)) } -func (s *service) importACLList(ctx context.Context) (err error) { - panic("not implemented") -} - func (s *service) CreateDocumentTree(ctx context.Context, aclListId string, text string) (id string, err error) { acc := s.account.Account() var ( diff --git a/service/storage/service.go b/service/storage/service.go index 5ee9efa4..fad4aa6d 100644 --- a/service/storage/service.go +++ b/service/storage/service.go @@ -2,13 +2,22 @@ package storage import ( "context" + "fmt" "github.com/anytypeio/go-anytype-infrastructure-experiments/app" + "github.com/anytypeio/go-anytype-infrastructure-experiments/app/logger" + "github.com/anytypeio/go-anytype-infrastructure-experiments/etc" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclchanges/aclpb" + "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/list" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage" + "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/testutils/acllistbuilder" + "github.com/anytypeio/go-anytype-infrastructure-experiments/service/account" + "github.com/anytypeio/go-anytype-infrastructure-experiments/service/node" ) var CName = "storage" +var log = logger.NewNamed("storage").Sugar() + type Service interface { storage.Provider } @@ -23,13 +32,18 @@ type service struct { func (s *service) Init(ctx context.Context, a *app.App) (err error) { s.storageProvider = storage.NewInMemoryTreeStorageProvider() - return nil + // importing hardcoded acl list, check that the keys there are correct + return s.importACLList(a) } func (s *service) Storage(treeId string) (storage.Storage, error) { return s.storageProvider.Storage(treeId) } +func (s *service) AddStorage(id string, st storage.Storage) error { + return s.storageProvider.AddStorage(id, st) +} + func (s *service) CreateTreeStorage(treeId string, header *aclpb.Header, changes []*aclpb.RawChange) (storage.TreeStorage, error) { return s.storageProvider.CreateTreeStorage(treeId, header, changes) } @@ -45,3 +59,51 @@ func (s *service) Run(ctx context.Context) (err error) { func (s service) Close(ctx context.Context) (err error) { return nil } + +func (s *service) importACLList(a *app.App) (err error) { + path := fmt.Sprintf("%s/%s", etc.Path(), "acl.yml") + st, err := acllistbuilder.NewACLListStorageBuilderFromFile(path) + if err != nil { + return err + } + + id, err := st.ID() + if err != nil { + return err + } + + // checking that acl list contains all the needed permissions for all our nodes + err = s.checkActualNodesPermissions(st, a) + if err != nil { + return err + } + + log.Infof("imported ACLList with id %s", id) + return s.storageProvider.AddStorage(id, st) +} + +func (s *service) checkActualNodesPermissions(st *acllistbuilder.ACLListStorageBuilder, a *app.App) error { + nodes := a.MustComponent(node.CName).(node.Service) + acc := a.MustComponent(account.CName).(account.Service) + + aclList, err := list.BuildACLListWithIdentity(acc.Account(), st) + if err != nil { + return err + } + + state := aclList.ACLState() + + // checking own state + if state.GetUserStates()[acc.Account().Identity].Permissions != aclpb.ACLChange_Admin { + return fmt.Errorf("own node with signing key %s should be admin", acc.Account().Identity) + } + + // checking other nodes' states + for _, n := range nodes.Nodes() { + if state.GetUserStates()[n.SigningKeyString].Permissions != aclpb.ACLChange_Admin { + return fmt.Errorf("other node with signing key %s should be admin", n.SigningKeyString) + } + } + + return nil +} diff --git a/syncproto/helpers.go b/syncproto/helpers.go index 9fe94914..57a1def0 100644 --- a/syncproto/helpers.go +++ b/syncproto/helpers.go @@ -1,8 +1,10 @@ package syncproto -import "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage/treepb" +import ( + "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclchanges/aclpb" +) -func WrapHeadUpdate(update *SyncHeadUpdate, header *treepb.TreeHeader, treeId string) *Sync { +func WrapHeadUpdate(update *SyncHeadUpdate, header *aclpb.Header, treeId string) *Sync { return &Sync{ Message: &SyncContentValue{ Value: &SyncContentValueValueOfHeadUpdate{HeadUpdate: update}, @@ -12,7 +14,7 @@ func WrapHeadUpdate(update *SyncHeadUpdate, header *treepb.TreeHeader, treeId st } } -func WrapFullRequest(request *SyncFullRequest, header *treepb.TreeHeader, treeId string) *Sync { +func WrapFullRequest(request *SyncFullRequest, header *aclpb.Header, treeId string) *Sync { return &Sync{ Message: &SyncContentValue{ Value: &SyncContentValueValueOfFullSyncRequest{FullSyncRequest: request}, @@ -22,7 +24,7 @@ func WrapFullRequest(request *SyncFullRequest, header *treepb.TreeHeader, treeId } } -func WrapFullResponse(response *SyncFullResponse, header *treepb.TreeHeader, treeId string) *Sync { +func WrapFullResponse(response *SyncFullResponse, header *aclpb.Header, treeId string) *Sync { return &Sync{ Message: &SyncContentValue{ Value: &SyncContentValueValueOfFullSyncResponse{FullSyncResponse: response},