Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ keywords = ["near", "smart contract", "plugin"]

[workspace.dependencies]
bitflags = "1.3"
near-sdk = "4.0.0"
# Feature `unstable` is required to use `near_sdk::store`.
near-sdk = { version = "4.0.0", features = ["unstable"] }
near-plugins-derive = { path = "near-plugins-derive" }
serde = "1"
anyhow = "1.0"
Expand Down
72 changes: 35 additions & 37 deletions near-plugins-derive/src/access_controllable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,25 +55,25 @@ pub fn access_controllable(attrs: TokenStream, item: TokenStream) -> TokenStream
#[derive(::near_sdk::borsh::BorshDeserialize, ::near_sdk::borsh::BorshSerialize)]
struct #acl_type {
/// Stores permissions per account.
permissions: ::near_sdk::collections::UnorderedMap<
permissions: ::near_sdk::store::UnorderedMap<
::near_sdk::AccountId,
#bitflags_type,
>,
/// Stores the set of accounts that bear a permission.
bearers: ::near_sdk::collections::UnorderedMap<
bearers: ::near_sdk::store::UnorderedMap<
#bitflags_type,
::near_sdk::collections::UnorderedSet<::near_sdk::AccountId>,
::near_sdk::store::UnorderedSet<::near_sdk::AccountId>,
>,
}

impl Default for #acl_type {
fn default() -> Self {
let base_prefix = <#ident as AccessControllable>::acl_storage_prefix();
Self {
permissions: ::near_sdk::collections::UnorderedMap::new(
permissions: ::near_sdk::store::UnorderedMap::new(
__acl_storage_prefix(base_prefix, __AclStorageKey::Permissions),
),
bearers: ::near_sdk::collections::UnorderedMap::new(
bearers: ::near_sdk::store::UnorderedMap::new(
__acl_storage_prefix(base_prefix, __AclStorageKey::Bearers),
),
}
Expand All @@ -99,17 +99,14 @@ pub fn access_controllable(attrs: TokenStream, item: TokenStream) -> TokenStream
}

impl #acl_type {
fn new_bearers_set(permission: #bitflags_type) -> ::near_sdk::collections::UnorderedSet<::near_sdk::AccountId> {
fn new_bearers_set(permission: #bitflags_type) -> ::near_sdk::store::UnorderedSet<::near_sdk::AccountId> {
let base_prefix = <#ident as AccessControllable>::acl_storage_prefix();
let specifier = __AclStorageKey::BearersSet { permission };
::near_sdk::collections::UnorderedSet::new(__acl_storage_prefix(base_prefix, specifier))
::near_sdk::store::UnorderedSet::new(__acl_storage_prefix(base_prefix, specifier))
}

fn get_or_init_permissions(&self, account_id: &::near_sdk::AccountId) -> #bitflags_type {
match self.permissions.get(account_id) {
Some(permissions) => permissions,
None => <#bitflags_type>::empty(),
}
fn get_or_insert_permissions(&mut self, account_id: ::near_sdk::AccountId) -> &mut #bitflags_type {
self.permissions.entry(account_id).or_insert_with(|| #bitflags_type::empty())
}

fn init_super_admin(&mut self, account_id: &::near_sdk::AccountId) -> bool {
Expand All @@ -136,12 +133,11 @@ pub fn access_controllable(attrs: TokenStream, item: TokenStream) -> TokenStream
fn add_super_admin_unchecked(&mut self, account_id: &::near_sdk::AccountId) -> bool {
let flag = <#bitflags_type>::from_bits(<#role_type>::acl_super_admin_permission())
.unwrap_or_else(|| ::near_sdk::env::panic_str(#ERR_PARSE_BITFLAG));
let mut permissions = self.get_or_init_permissions(account_id);
let mut permissions = self.get_or_insert_permissions(account_id.clone());

let is_new_super_admin = !permissions.contains(flag);
if is_new_super_admin {
permissions.insert(flag);
self.permissions.insert(account_id, &permissions);
self.add_bearer(flag, account_id);

let event = ::#cratename::access_controllable::events::SuperAdminAdded {
Expand Down Expand Up @@ -171,12 +167,14 @@ pub fn access_controllable(attrs: TokenStream, item: TokenStream) -> TokenStream
fn revoke_super_admin_unchecked(&mut self, account_id: &::near_sdk::AccountId) -> bool {
let flag = <#bitflags_type>::from_bits(<#role_type>::acl_super_admin_permission())
.unwrap_or_else(|| ::near_sdk::env::panic_str(#ERR_PARSE_BITFLAG));
let mut permissions = self.get_or_init_permissions(account_id);
let mut permissions = match self.permissions.get_mut(account_id) {
Some(permissions) => permissions,
None => return false, // nothing to do, account has no permissions
};

let was_super_admin = permissions.contains(flag);
if was_super_admin {
permissions.remove(flag);
self.permissions.insert(account_id, &permissions);
self.remove_bearer(flag, account_id);

let event = ::#cratename::access_controllable::events::SuperAdminRevoked {
Expand All @@ -203,12 +201,11 @@ pub fn access_controllable(attrs: TokenStream, item: TokenStream) -> TokenStream
fn add_admin_unchecked(&mut self, role: #role_type, account_id: &::near_sdk::AccountId) -> bool {
let flag = <#bitflags_type>::from_bits(role.acl_admin_permission())
.unwrap_or_else(|| ::near_sdk::env::panic_str(#ERR_PARSE_BITFLAG));
let mut permissions = self.get_or_init_permissions(account_id);
let mut permissions = self.get_or_insert_permissions(account_id.clone());

let is_new_admin = !permissions.contains(flag);
if is_new_admin {
permissions.insert(flag);
self.permissions.insert(account_id, &permissions);
self.add_bearer(flag, account_id);

let event = ::#cratename::access_controllable::events::AdminAdded {
Expand Down Expand Up @@ -252,12 +249,14 @@ pub fn access_controllable(attrs: TokenStream, item: TokenStream) -> TokenStream
fn revoke_admin_unchecked(&mut self, role: #role_type, account_id: &::near_sdk::AccountId) -> bool {
let flag = <#bitflags_type>::from_bits(role.acl_admin_permission())
.unwrap_or_else(|| ::near_sdk::env::panic_str(#ERR_PARSE_BITFLAG));
let mut permissions = self.get_or_init_permissions(account_id);
let mut permissions = match self.permissions.get_mut(account_id) {
Some(permissions) => permissions,
None => return false, // nothing to do, account has no permissions
};

let was_admin = permissions.contains(flag);
if was_admin {
permissions.remove(flag);
self.permissions.insert(account_id, &permissions);
self.remove_bearer(flag, account_id);

let event = ::#cratename::access_controllable::events::AdminRevoked {
Expand All @@ -283,12 +282,11 @@ pub fn access_controllable(attrs: TokenStream, item: TokenStream) -> TokenStream
fn grant_role_unchecked(&mut self, role: #role_type, account_id: &::near_sdk::AccountId) -> bool {
let flag = <#bitflags_type>::from_bits(role.acl_permission())
.unwrap_or_else(|| ::near_sdk::env::panic_str(#ERR_PARSE_BITFLAG));
let mut permissions = self.get_or_init_permissions(account_id);
let mut permissions = self.get_or_insert_permissions(account_id.clone());

let is_new_grantee = !permissions.contains(flag);
if is_new_grantee {
permissions.insert(flag);
self.permissions.insert(account_id, &permissions);
self.add_bearer(flag, account_id);

let event = ::#cratename::access_controllable::events::RoleGranted {
Expand Down Expand Up @@ -316,12 +314,14 @@ pub fn access_controllable(attrs: TokenStream, item: TokenStream) -> TokenStream
fn revoke_role_unchecked(&mut self, role: #role_type, account_id: &::near_sdk::AccountId) -> bool {
let flag = <#bitflags_type>::from_bits(role.acl_permission())
.unwrap_or_else(|| ::near_sdk::env::panic_str(#ERR_PARSE_BITFLAG));
let mut permissions = self.get_or_init_permissions(account_id);
let mut permissions = match self.permissions.get_mut(account_id) {
Some(permissions) => permissions,
None => return false, // nothing to do, account has no permissions
};

let was_grantee = permissions.contains(flag);
if was_grantee {
permissions.remove(flag);
self.permissions.insert(account_id, &permissions);
self.remove_bearer(flag, account_id);

let event = ::#cratename::access_controllable::events::RoleRevoked {
Expand Down Expand Up @@ -365,7 +365,10 @@ pub fn access_controllable(attrs: TokenStream, item: TokenStream) -> TokenStream
}

fn has_any_permission(&self, target: #bitflags_type, account_id: &::near_sdk::AccountId) -> bool {
let permissions = self.get_or_init_permissions(account_id);
let permissions = match self.permissions.get(account_id) {
Some(&permissions) => permissions,
None => return false,
};
target.intersects(permissions)
}

Expand All @@ -383,13 +386,10 @@ pub fn access_controllable(attrs: TokenStream, item: TokenStream) -> TokenStream
permission.bits().is_power_of_two(),
"Adding a bearer is allowed only for permissions with exactly one active bit"
);
let mut set = match self.bearers.get(&permission) {
Some(set) => set,
None => Self::new_bearers_set(permission),
};
if let true = set.insert(account_id) {
self.bearers.insert(&permission, &set);
}
let mut set = self.bearers.entry(permission).or_insert_with(|| {
Self::new_bearers_set(permission)
});
set.insert(account_id.clone());
}

/// Enables paginated retrieval of bearers. Returns up to `limit`
Expand All @@ -405,20 +405,18 @@ pub fn access_controllable(attrs: TokenStream, item: TokenStream) -> TokenStream
Some(set) => set,
None => return vec![],
};
set.iter().skip(skip).take(limit).collect()
set.iter().skip(skip).take(limit).cloned().collect()
}

/// Removes `account_id` from the set of `permission` bearers.
fn remove_bearer(&mut self, permission: #bitflags_type, account_id: &::near_sdk::AccountId) {
// If `permission` is invalid (more than one active bit), this
// function is a no-op, due to the check in `add_bearer`.
let mut set = match self.bearers.get(&permission) {
let mut set = match self.bearers.get_mut(&permission) {
Some(set) => set,
None => return,
};
if let true = set.remove(account_id) {
self.bearers.insert(&permission, &set);
}
set.remove(account_id);
}
}

Expand Down