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
56 changes: 36 additions & 20 deletions contracts/access-control/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ mod test;
#[repr(u32)]
pub enum ContractError {
InvalidDidFormat = 1,
AlreadyInitialized = 2,
EntityAlreadyRegistered = 3,
GrantorNotRegistered = 4,
GranteeNotRegistered = 5,
AccessAlreadyGranted = 6,
NotAuthorizedToRevoke = 7,
AccessPermissionNotFound = 8,
ContractNotInitialized = 9,
OnlyAdminCanDeactivate = 10,
EntityNotFound = 11,
}

/// --------------------
Expand Down Expand Up @@ -73,15 +83,16 @@ impl AccessControl {
///
/// # Arguments
/// * `admin` - The admin address for the contract
pub fn initialize(env: Env, admin: Address) {
pub fn initialize(env: Env, admin: Address) -> Result<(), ContractError> {
if env.storage().persistent().has(&DataKey::Admin) {
panic!("Contract already initialized");
return Err(ContractError::AlreadyInitialized);
}
admin.require_auth();
env.storage().persistent().set(&DataKey::Admin, &admin);

env.events()
.publish((symbol_short!("init"), admin), symbol_short!("success"));
Ok(())
}

/// Register a new entity in the system
Expand All @@ -97,12 +108,12 @@ impl AccessControl {
entity_type: EntityType,
name: String,
metadata: String,
) {
) -> Result<(), ContractError> {
wallet.require_auth();

let key = DataKey::Entity(wallet.clone());
if env.storage().persistent().has(&key) {
panic!("Entity already registered");
return Err(ContractError::EntityAlreadyRegistered);
}

let entity = EntityData {
Expand All @@ -122,6 +133,7 @@ impl AccessControl {

env.events()
.publish((symbol_short!("reg_ent"), wallet), symbol_short!("success"));
Ok(())
}

/// Grant access permission to an entity for a specific resource
Expand All @@ -137,19 +149,19 @@ impl AccessControl {
grantee: Address,
resource_id: String,
expires_at: u64,
) {
) -> Result<(), ContractError> {
grantor.require_auth();

// Verify grantor is a registered entity
let grantor_key = DataKey::Entity(grantor.clone());
if !env.storage().persistent().has(&grantor_key) {
panic!("Grantor not registered");
return Err(ContractError::GrantorNotRegistered);
}

// Verify grantee is a registered entity
let grantee_key = DataKey::Entity(grantee.clone());
if !env.storage().persistent().has(&grantee_key) {
panic!("Grantee not registered");
return Err(ContractError::GranteeNotRegistered);
}

let permission = AccessPermission {
Expand Down Expand Up @@ -178,7 +190,7 @@ impl AccessControl {
}
}
if exists {
panic!("Access already granted for this resource");
return Err(ContractError::AccessAlreadyGranted);
}

access_list.push_back(permission);
Expand All @@ -199,6 +211,7 @@ impl AccessControl {
(symbol_short!("grant"), grantee, resource_id),
symbol_short!("success"),
);
Ok(())
}

/// Revoke access permission from an entity for a specific resource
Expand All @@ -207,15 +220,15 @@ impl AccessControl {
/// * `revoker` - The address revoking access (must be the original grantor or admin)
/// * `revokee` - The address losing access
/// * `resource_id` - The identifier of the resource
pub fn revoke_access(env: Env, revoker: Address, revokee: Address, resource_id: String) {
pub fn revoke_access(env: Env, revoker: Address, revokee: Address, resource_id: String) -> Result<(), ContractError> {
revoker.require_auth();

// Get admin for authorization check
let admin: Address = env
.storage()
.persistent()
.get(&DataKey::Admin)
.expect("Contract not initialized");
.ok_or(ContractError::ContractNotInitialized)?;

// Remove from grantee's access list
let access_key = DataKey::AccessList(revokee.clone());
Expand All @@ -233,7 +246,7 @@ impl AccessControl {
if permission.resource_id == resource_id {
// Verify revoker is either the original grantor or admin
if permission.granted_by != revoker && revoker != admin {
panic!("Not authorized to revoke this access");
return Err(ContractError::NotAuthorizedToRevoke);
}
found = true;
// Skip this permission (effectively removing it)
Expand All @@ -244,7 +257,7 @@ impl AccessControl {
}

if !found {
panic!("Access permission not found");
return Err(ContractError::AccessPermissionNotFound);
}

env.storage()
Expand Down Expand Up @@ -275,6 +288,7 @@ impl AccessControl {
(symbol_short!("revoke"), revokee, resource_id),
symbol_short!("success"),
);
Ok(())
}

/// Check if an entity has access to a specific resource
Expand Down Expand Up @@ -331,12 +345,12 @@ impl AccessControl {
///
/// # Returns
/// The EntityData for the given wallet address
pub fn get_entity(env: Env, wallet: Address) -> EntityData {
pub fn get_entity(env: Env, wallet: Address) -> Result<EntityData, ContractError> {
let key = DataKey::Entity(wallet);
env.storage()
.persistent()
.get(&key)
.expect("Entity not found")
.ok_or(ContractError::EntityNotFound)
}

/// Get all access permissions for an entity
Expand All @@ -359,53 +373,55 @@ impl AccessControl {
/// # Arguments
/// * `wallet` - The wallet address of the entity
/// * `metadata` - Updated metadata information
pub fn update_entity(env: Env, wallet: Address, metadata: String) {
pub fn update_entity(env: Env, wallet: Address, metadata: String) -> Result<(), ContractError> {
wallet.require_auth();

let key = DataKey::Entity(wallet.clone());
let mut entity: EntityData = env
.storage()
.persistent()
.get(&key)
.expect("Entity not found");
.ok_or(ContractError::EntityNotFound)?;

entity.metadata = metadata;
env.storage().persistent().set(&key, &entity);

env.events()
.publish((symbol_short!("upd_ent"), wallet), symbol_short!("success"));
Ok(())
}

/// Deactivate an entity (admin only)
///
/// # Arguments
/// * `admin` - The admin address
/// * `wallet` - The wallet address of the entity to deactivate
pub fn deactivate_entity(env: Env, admin: Address, wallet: Address) {
pub fn deactivate_entity(env: Env, admin: Address, wallet: Address) -> Result<(), ContractError> {
admin.require_auth();

let stored_admin: Address = env
.storage()
.persistent()
.get(&DataKey::Admin)
.expect("Contract not initialized");
.ok_or(ContractError::ContractNotInitialized)?;

if admin != stored_admin {
panic!("Only admin can deactivate entities");
return Err(ContractError::OnlyAdminCanDeactivate);
}

let key = DataKey::Entity(wallet.clone());
let mut entity: EntityData = env
.storage()
.persistent()
.get(&key)
.expect("Entity not found");
.ok_or(ContractError::EntityNotFound)?;

entity.active = false;
env.storage().persistent().set(&key, &entity);

env.events()
.publish((symbol_short!("deact"), wallet), symbol_short!("success"));
Ok(())
}

/// Register or update a W3C DID for the provided address.
Expand Down
Loading
Loading