[#118] frostfsid: Restrict keys to a single subject
All checks were successful
DCO action / DCO (pull_request) Successful in 45s
Code generation / Generate wrappers (pull_request) Successful in 1m6s
Tests / Tests (pull_request) Successful in 1m25s

Signed-off-by: Alexander Chuprov <a.chuprov@yadro.com>
This commit is contained in:
Alexander Chuprov 2024-10-30 18:02:08 +03:00
parent 5f956751d4
commit a98caa7210
Signed by: achuprov
GPG key ID: 2D916FFD803B0EDD
2 changed files with 58 additions and 0 deletions

View file

@ -96,6 +96,8 @@ const (
groupSubjectsKeysPrefix = 'G' groupSubjectsKeysPrefix = 'G'
groupCounterKey = 'c' groupCounterKey = 'c'
namespaceGroupsNamesPrefix = 'm' namespaceGroupsNamesPrefix = 'm'
// allAddressPrefix contains all keys and signifies that the key has been used.
allAddressPrefix = 'A'
) )
func _deploy(data any, isUpdate bool) { func _deploy(data any, isUpdate bool) {
@ -182,6 +184,11 @@ func CreateSubject(ns string, key interop.PublicKey) {
panic("key is occupied") panic("key is occupied")
} }
allAddressKey := allAddress(addr)
if storage.Get(ctx, allAddressKey) != nil {
panic("key is occupied")
}
nsKey := namespaceKey(ns) nsKey := namespaceKey(ns)
data = storage.Get(ctx, nsKey).([]byte) data = storage.Get(ctx, nsKey).([]byte)
if data == nil { if data == nil {
@ -197,6 +204,7 @@ func CreateSubject(ns string, key interop.PublicKey) {
nsSubjKey := namespaceSubjectKey(ns, addr) nsSubjKey := namespaceSubjectKey(ns, addr)
storage.Put(ctx, nsSubjKey, []byte{1}) storage.Put(ctx, nsSubjKey, []byte{1})
storage.Put(ctx, allAddressKey, true)
runtime.Notify("CreateSubject", interop.Hash160(addr)) runtime.Notify("CreateSubject", interop.Hash160(addr))
} }
@ -213,6 +221,11 @@ func AddSubjectKey(addr interop.Hash160, key interop.PublicKey) {
panic("incorrect public key length") panic("incorrect public key length")
} }
allAddressKey := allAddress(contract.CreateStandardAccount(key))
if storage.Get(ctx, allAddressKey) != nil {
panic("key is occupied")
}
saKey := subjectAdditionalKey(key, addr) saKey := subjectAdditionalKey(key, addr)
data := storage.Get(ctx, saKey).([]byte) data := storage.Get(ctx, saKey).([]byte)
if data != nil { if data != nil {
@ -230,6 +243,7 @@ func AddSubjectKey(addr interop.Hash160, key interop.PublicKey) {
subject.AdditionalKeys = append(subject.AdditionalKeys, key) subject.AdditionalKeys = append(subject.AdditionalKeys, key)
storage.Put(ctx, sKey, std.Serialize(subject)) storage.Put(ctx, sKey, std.Serialize(subject))
storage.Put(ctx, allAddressKey, true)
runtime.Notify("AddSubjectKey", addr, key) runtime.Notify("AddSubjectKey", addr, key)
} }
@ -269,6 +283,7 @@ func RemoveSubjectKey(addr interop.Hash160, key interop.PublicKey) {
subject.AdditionalKeys = additionalKeys subject.AdditionalKeys = additionalKeys
storage.Put(ctx, sKey, std.Serialize(subject)) storage.Put(ctx, sKey, std.Serialize(subject))
storage.Delete(ctx, allAddress(contract.CreateStandardAccount(key)))
runtime.Notify("RemoveSubjectKey", addr, key) runtime.Notify("RemoveSubjectKey", addr, key)
} }
@ -362,6 +377,7 @@ func DeleteSubject(addr interop.Hash160) {
for i := 0; i < len(subj.AdditionalKeys); i++ { for i := 0; i < len(subj.AdditionalKeys); i++ {
storage.Delete(ctx, subjectAdditionalKey(subj.AdditionalKeys[i], addr)) storage.Delete(ctx, subjectAdditionalKey(subj.AdditionalKeys[i], addr))
storage.Delete(ctx, allAddress(contract.CreateStandardAccount(subj.AdditionalKeys[i])))
} }
storage.Delete(ctx, sKey) storage.Delete(ctx, sKey)
@ -1001,3 +1017,7 @@ func idToBytes(itemID int) []byte {
zeros := make([]byte, 8-ln) zeros := make([]byte, 8-ln)
return append(b, zeros...) return append(b, zeros...)
} }
func allAddress(address []byte) []byte {
return append([]byte{allAddressPrefix}, address...)
}

View file

@ -604,6 +604,44 @@ func TestFrostFSID_GroupManagement(t *testing.T) {
}) })
} }
func TestAdditionalKeyFromPrimarySubject(t *testing.T) {
f := newFrostFSIDInvoker(t)
invoker := f.OwnerInvoker()
subjAPrimaryKey, err := keys.NewPrivateKey()
require.NoError(t, err)
subjAKeyAddr := subjAPrimaryKey.PublicKey().GetScriptHash()
subjBPrimaryKey, err := keys.NewPrivateKey()
require.NoError(t, err)
subjBKeyAddr := subjBPrimaryKey.PublicKey().GetScriptHash()
subjCPrimaryKey, err := keys.NewPrivateKey()
require.NoError(t, err)
subjDPrimaryKey, err := keys.NewPrivateKey()
require.NoError(t, err)
invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, defaultNamespace, subjAPrimaryKey.PublicKey().Bytes())
invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, defaultNamespace, subjBPrimaryKey.PublicKey().Bytes())
invoker.InvokeFail(t, "key is occupied", addSubjectKeyMethod, subjBKeyAddr, subjAPrimaryKey.PublicKey().Bytes())
invoker.Invoke(t, stackitem.Null{}, addSubjectKeyMethod, subjAKeyAddr, subjCPrimaryKey.PublicKey().Bytes())
invoker.InvokeFail(t, "key is occupied", addSubjectKeyMethod, subjBKeyAddr, subjCPrimaryKey.PublicKey().Bytes())
invoker.Invoke(t, stackitem.Null{}, addSubjectKeyMethod, subjAKeyAddr, subjDPrimaryKey.PublicKey().Bytes())
invoker.InvokeFail(t, "key is occupied", addSubjectKeyMethod, subjBKeyAddr, subjDPrimaryKey.PublicKey().Bytes())
invoker.Invoke(t, stackitem.Null{}, removeSubjectKeyMethod, subjAKeyAddr, subjDPrimaryKey.PublicKey().Bytes())
invoker.Invoke(t, stackitem.Null{}, addSubjectKeyMethod, subjBKeyAddr, subjDPrimaryKey.PublicKey().Bytes())
invoker.InvokeFail(t, "key is occupied", addSubjectKeyMethod, subjAKeyAddr, subjDPrimaryKey.PublicKey().Bytes())
invoker.Invoke(t, stackitem.Null{}, deleteSubjectMethod, subjBKeyAddr)
invoker.Invoke(t, stackitem.Null{}, addSubjectKeyMethod, subjAKeyAddr, subjDPrimaryKey.PublicKey().Bytes())
}
func checkPublicKeyResult(t *testing.T, s *vm.Stack, err error, key *keys.PrivateKey) { func checkPublicKeyResult(t *testing.T, s *vm.Stack, err error, key *keys.PrivateKey) {
if key == nil { if key == nil {
require.ErrorContains(t, err, "not found") require.ErrorContains(t, err, "not found")