forked from TrueCloudLab/frostfs-contract
[#174] subnet: Add RemoveUser
method
Signed-off-by: Pavel Karpy <carpawell@nspcc.ru>
This commit is contained in:
parent
9a05e213eb
commit
a7a272ad08
2 changed files with 93 additions and 51 deletions
|
@ -31,6 +31,8 @@ const (
|
||||||
ErrClientAdmNotExist = "client admin not found"
|
ErrClientAdmNotExist = "client admin not found"
|
||||||
// ErrNodeNotExist is thrown when node is not found.
|
// ErrNodeNotExist is thrown when node is not found.
|
||||||
ErrNodeNotExist = "node not found"
|
ErrNodeNotExist = "node not found"
|
||||||
|
// ErrUserNotExist is thrown when user is not found.
|
||||||
|
ErrUserNotExist = "user not found"
|
||||||
// ErrAccessDenied is thrown when operation is denied for caller.
|
// ErrAccessDenied is thrown when operation is denied for caller.
|
||||||
ErrAccessDenied = "access denied"
|
ErrAccessDenied = "access denied"
|
||||||
|
|
||||||
|
@ -228,31 +230,18 @@ func AddNode(subnetID []byte, node interop.PublicKey) {
|
||||||
ctx := storage.GetContext()
|
ctx := storage.GetContext()
|
||||||
|
|
||||||
stKey := append([]byte{ownerPrefix}, subnetID...)
|
stKey := append([]byte{ownerPrefix}, subnetID...)
|
||||||
prefixLen := len(stKey)
|
|
||||||
|
|
||||||
rawOwner := storage.Get(ctx, stKey)
|
rawOwner := storage.Get(ctx, stKey)
|
||||||
if rawOwner == nil {
|
if rawOwner == nil {
|
||||||
panic("addNode: " + ErrSubNotExist)
|
panic("addNode: " + ErrSubNotExist)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stKey[0] = nodeAdminPrefix
|
||||||
|
|
||||||
owner := rawOwner.([]byte)
|
owner := rawOwner.([]byte)
|
||||||
if !runtime.CheckWitness(owner) {
|
|
||||||
var hasAccess bool
|
|
||||||
|
|
||||||
stKey[0] = nodeAdminPrefix
|
if !calledByOwnerOrAdmin(ctx, owner, stKey) {
|
||||||
|
panic("addNode: " + ErrAccessDenied)
|
||||||
iter := storage.Find(ctx, stKey, storage.KeysOnly)
|
|
||||||
for iterator.Next(iter) {
|
|
||||||
key := iterator.Value(iter).([]byte)
|
|
||||||
if runtime.CheckWitness(key[prefixLen:]) {
|
|
||||||
hasAccess = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !hasAccess {
|
|
||||||
panic("addNode: " + ErrAccessDenied)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stKey[0] = nodePrefix
|
stKey[0] = nodePrefix
|
||||||
|
@ -275,31 +264,18 @@ func RemoveNode(subnetID []byte, node interop.PublicKey) {
|
||||||
ctx := storage.GetContext()
|
ctx := storage.GetContext()
|
||||||
|
|
||||||
stKey := append([]byte{ownerPrefix}, subnetID...)
|
stKey := append([]byte{ownerPrefix}, subnetID...)
|
||||||
prefixLen := len(stKey)
|
|
||||||
|
|
||||||
rawOwner := storage.Get(ctx, stKey)
|
rawOwner := storage.Get(ctx, stKey)
|
||||||
if rawOwner == nil {
|
if rawOwner == nil {
|
||||||
panic("removeNode: " + ErrSubNotExist)
|
panic("removeNode: " + ErrSubNotExist)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stKey[0] = nodeAdminPrefix
|
||||||
|
|
||||||
owner := rawOwner.([]byte)
|
owner := rawOwner.([]byte)
|
||||||
if !runtime.CheckWitness(owner) {
|
|
||||||
var hasAccess bool
|
|
||||||
|
|
||||||
stKey[0] = nodeAdminPrefix
|
if !calledByOwnerOrAdmin(ctx, owner, stKey) {
|
||||||
|
panic("removeNode: " + ErrAccessDenied)
|
||||||
iter := storage.Find(ctx, stKey, storage.KeysOnly)
|
|
||||||
for iterator.Next(iter) {
|
|
||||||
key := iterator.Value(iter).([]byte)
|
|
||||||
if runtime.CheckWitness(key[prefixLen:]) {
|
|
||||||
hasAccess = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !hasAccess {
|
|
||||||
panic("removeNode: " + ErrAccessDenied)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stKey[0] = nodePrefix
|
stKey[0] = nodePrefix
|
||||||
|
@ -413,27 +389,13 @@ func AddUser(subnetID []byte, groupID []byte, userID []byte) {
|
||||||
panic("addUser: " + ErrSubNotExist)
|
panic("addUser: " + ErrSubNotExist)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stKey[0] = clientAdminPrefix
|
||||||
stKey = append(stKey, groupID...)
|
stKey = append(stKey, groupID...)
|
||||||
prefixLen := len(stKey)
|
|
||||||
|
|
||||||
owner := rawOwner.([]byte)
|
owner := rawOwner.([]byte)
|
||||||
if !runtime.CheckWitness(owner) {
|
|
||||||
var hasAccess bool
|
|
||||||
|
|
||||||
stKey[0] = clientAdminPrefix
|
if !calledByOwnerOrAdmin(ctx, owner, stKey) {
|
||||||
|
panic("addUser: " + ErrAccessDenied)
|
||||||
iter := storage.Find(ctx, stKey, storage.KeysOnly)
|
|
||||||
for iterator.Next(iter) {
|
|
||||||
key := iterator.Value(iter).([]byte)
|
|
||||||
if runtime.CheckWitness(key[prefixLen:]) {
|
|
||||||
hasAccess = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !hasAccess {
|
|
||||||
panic("addUser: " + ErrAccessDenied)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stKey[0] = userPrefix
|
stKey[0] = userPrefix
|
||||||
|
@ -445,6 +407,41 @@ func AddUser(subnetID []byte, groupID []byte, userID []byte) {
|
||||||
putKeyInList(ctx, userID, stKey)
|
putKeyInList(ctx, userID, stKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RemoveUser removes user from the specified subnetwork and group.
|
||||||
|
// Must be called by the owner or the group's admin only.
|
||||||
|
func RemoveUser(subnetID []byte, groupID []byte, userID []byte) {
|
||||||
|
// V2 format check
|
||||||
|
if len(userID) != userIDSize {
|
||||||
|
panic("addUser: " + ErrInvalidUser)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := storage.GetContext()
|
||||||
|
|
||||||
|
stKey := append([]byte{ownerPrefix}, subnetID...)
|
||||||
|
|
||||||
|
rawOwner := storage.Get(ctx, stKey)
|
||||||
|
if rawOwner == nil {
|
||||||
|
panic("removeUser: " + ErrSubNotExist)
|
||||||
|
}
|
||||||
|
|
||||||
|
stKey[0] = clientAdminPrefix
|
||||||
|
stKey = append(stKey, groupID...)
|
||||||
|
|
||||||
|
owner := rawOwner.([]byte)
|
||||||
|
|
||||||
|
if !calledByOwnerOrAdmin(ctx, owner, stKey) {
|
||||||
|
panic("removeUser: " + ErrAccessDenied)
|
||||||
|
}
|
||||||
|
|
||||||
|
stKey[0] = userPrefix
|
||||||
|
|
||||||
|
if !keyInList(ctx, userID, stKey) {
|
||||||
|
panic("removeUser: " + ErrUserNotExist)
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteKeyFromList(ctx, userID, stKey)
|
||||||
|
}
|
||||||
|
|
||||||
// Version returns version of the contract.
|
// Version returns version of the contract.
|
||||||
func Version() int {
|
func Version() int {
|
||||||
return common.Version
|
return common.Version
|
||||||
|
@ -461,3 +458,21 @@ func putKeyInList(ctx storage.Context, keyToPut interop.PublicKey, prefix []byte
|
||||||
func deleteKeyFromList(ctx storage.Context, keyToDelete interop.PublicKey, prefix []byte) {
|
func deleteKeyFromList(ctx storage.Context, keyToDelete interop.PublicKey, prefix []byte) {
|
||||||
storage.Delete(ctx, append(prefix, keyToDelete...))
|
storage.Delete(ctx, append(prefix, keyToDelete...))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func calledByOwnerOrAdmin(ctx storage.Context, owner []byte, adminPrefix []byte) bool {
|
||||||
|
if runtime.CheckWitness(owner) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
prefixLen := len(adminPrefix)
|
||||||
|
|
||||||
|
iter := storage.Find(ctx, adminPrefix, storage.KeysOnly)
|
||||||
|
for iterator.Next(iter) {
|
||||||
|
key := iterator.Value(iter).([]byte)
|
||||||
|
if runtime.CheckWitness(key[prefixLen:]) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
|
@ -258,6 +258,33 @@ func TestSubnet_AddUser(t *testing.T) {
|
||||||
cOwn.InvokeFail(t, method+errSeparator+"user has already been added", method, id, groupId, user)
|
cOwn.InvokeFail(t, method+errSeparator+"user has already been added", method, id, groupId, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSubnet_RemoveUser(t *testing.T) {
|
||||||
|
e := newSubnetInvoker(t)
|
||||||
|
|
||||||
|
id, owner := createSubnet(t, e)
|
||||||
|
|
||||||
|
groupId := randomBytes(8)
|
||||||
|
user := randomBytes(27)
|
||||||
|
|
||||||
|
adm := e.NewAccount(t)
|
||||||
|
admPub, ok := vm.ParseSignatureContract(adm.Script())
|
||||||
|
require.True(t, ok)
|
||||||
|
|
||||||
|
const method = "removeUser"
|
||||||
|
|
||||||
|
cOwn := e.WithSigners(owner)
|
||||||
|
cOwn.InvokeFail(t, method+errSeparator+subnet.ErrSubNotExist, method, []byte{0, 0, 0, 0}, groupId, user)
|
||||||
|
|
||||||
|
cOwn.InvokeFail(t, method+errSeparator+subnet.ErrUserNotExist, method, id, groupId, user)
|
||||||
|
cOwn.Invoke(t, stackitem.Null{}, "addUser", id, groupId, user)
|
||||||
|
cOwn.Invoke(t, stackitem.Null{}, method, id, groupId, user)
|
||||||
|
|
||||||
|
cAdm := cOwn.WithSigners(adm)
|
||||||
|
|
||||||
|
cOwn.Invoke(t, stackitem.Null{}, "addClientAdmin", id, groupId, admPub)
|
||||||
|
cAdm.InvokeFail(t, method+errSeparator+subnet.ErrUserNotExist, method, id, groupId, user)
|
||||||
|
}
|
||||||
|
|
||||||
func createSubnet(t *testing.T, e *neotest.ContractInvoker) (id []byte, owner neotest.Signer) {
|
func createSubnet(t *testing.T, e *neotest.ContractInvoker) (id []byte, owner neotest.Signer) {
|
||||||
var (
|
var (
|
||||||
ok bool
|
ok bool
|
||||||
|
|
Loading…
Reference in a new issue