Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Acl): add acl_add_super_admin #98

Merged
merged 2 commits into from
Mar 15, 2023
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
11 changes: 11 additions & 0 deletions near-plugins-derive/src/access_controllable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,13 @@ pub fn access_controllable(attrs: TokenStream, item: TokenStream) -> TokenStream
res
}

fn add_super_admin(&mut self, account_id: &::near_sdk::AccountId) -> Option<bool> {
if !self.is_super_admin(&::near_sdk::env::predecessor_account_id()) {
return None;
}
Some(self.add_super_admin_unchecked(account_id))
}

/// Makes `account_id` a super-admin __without__ checking any permissions.
/// It returns whether `account_id` is a new super-admin.
///
Expand Down Expand Up @@ -563,6 +570,10 @@ pub fn access_controllable(attrs: TokenStream, item: TokenStream) -> TokenStream
self.acl_get_or_init().init_super_admin(&account_id)
}

fn acl_add_super_admin(&mut self, account_id: ::near_sdk::AccountId) -> Option<bool> {
self.acl_get_or_init().add_super_admin(&account_id)
}

fn acl_role_variants(&self) -> Vec<&'static str> {
<#role_type>::acl_role_variants()
}
Expand Down
41 changes: 41 additions & 0 deletions near-plugins-derive/tests/access_controllable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,47 @@ async fn test_acl_init_super_admin() -> anyhow::Result<()> {
Ok(())
}

#[tokio::test]
async fn test_acl_add_super_admin() -> anyhow::Result<()> {
let setup = Setup::new().await?;
let to_be_super_admin = setup.worker.dev_create_account().await?;

// Create accounts that add a super-admin.
let caller_unauth = setup.worker.dev_create_account().await?;
let caller_auth = setup.new_super_admin_account().await?;

// Adding is a no-op if the caller is not a super-admin.
let res = setup
.contract
.acl_add_super_admin(&caller_unauth, to_be_super_admin.id())
.await?;
assert_eq!(res, None);
setup
.contract
.assert_acl_is_super_admin(false, setup.contract_account(), to_be_super_admin.id())
.await;

// Adding succeeds if the caller is a super-admin.
let res = setup
.contract
.acl_add_super_admin(&caller_auth, to_be_super_admin.id())
.await?;
assert_eq!(res, Some(true));
setup
.contract
.assert_acl_is_super_admin(true, setup.contract_account(), to_be_super_admin.id())
.await;

// Adding an account which is already super-admin returns `Some(false)`.
let res = setup
.contract
.acl_add_super_admin(&caller_auth, to_be_super_admin.id())
.await?;
assert_eq!(res, Some(false));

Ok(())
}

#[tokio::test]
async fn test_acl_add_super_admin_unchecked() -> anyhow::Result<()> {
let Setup {
Expand Down
18 changes: 18 additions & 0 deletions near-plugins-derive/tests/common/access_controllable_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,24 @@ impl AccessControllableContract {
.await
}

pub async fn acl_add_super_admin(
&self,
caller: &Account,
account_id: &AccountId,
) -> anyhow::Result<Option<bool>> {
let res = caller
.call(self.contract.id(), "acl_add_super_admin")
.args_json(json!({
"account_id": account_id,
}))
.max_gas()
.transact()
.await?
.into_result()?
.json::<Option<bool>>()?;
Ok(res)
}

pub async fn acl_add_super_admin_unchecked(
&self,
caller: &Account,
Expand Down
33 changes: 28 additions & 5 deletions near-plugins/src/access_controllable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ pub trait AccessControllable {
/// It is `#[private]` in the implementation provided by this trait, i.e.
/// only the contract itself may call this method.
///
/// Despite the restrictions of this method, it is possible to add multiple
/// super-admins using [`acl_add_super_admin`].
///
/// If a super-admin is added, the following event will be emitted:
///
/// ```json
Expand All @@ -71,13 +74,33 @@ pub trait AccessControllable {
/// }
/// }
/// ```
///
/// Despite the restrictions of this method, there might be multiple
/// super-admins. Adding more than one admin requires the use of internal
/// methods. The default implementation of `AccessControllable` provided by
/// this trait offers `add_super_admin_unchecked.`
fn acl_init_super_admin(&mut self, account_id: AccountId) -> bool;

/// Adds `account_id` as super-admin provided that the predecessor has sufficient permissions,
/// i.e. is a super-admin as defined by [`acl_is_super_admin`]. To add the first super-admin,
/// [`acl_init_super_admin`] can be used.
///
/// In case of sufficient permissions, the returned `Some(bool)` indicates whether `account_id`
/// is a new super-admin. Without permissions, `None` is returned and internal state is not
/// modified.
///
/// Note that there may be multiple (or zero) super-admins.
///
/// If a super-admin is added, the following event will be emitted:
///
/// ```json
/// {
/// "standard":"AccessControllable",
/// "version":"1.0.0",
/// "event":"super_admin_added",
/// "data":{
/// "account":"<NEW_SUPER_ADMIN>",
/// "by":"<SUPER_ADMIN>"
/// }
/// }
/// ```
fn acl_add_super_admin(&mut self, account_id: AccountId) -> Option<bool>;

/// Returns whether `account_id` is a super-admin. A super-admin has admin
/// permissions for every role. However, a super-admin is not considered
/// grantee of any role.
Expand Down