@inkwell.ar/sdk
Version:
SDK for interacting with the Inkwell Blog CRUD AO process using aoconnect for deployment and interactions
2 lines • 14.2 kB
TypeScript
export declare const ACCESS_CONTROL_CONTRACT = "-- AccessControl library for AO processes\n-- Similar to OpenZeppelin's AccessControl contract\n\nName = \"Access Control\"\nAuthor = \"@7i7o\"\n\nlocal AccessControl = {}\nlocal is_initialized = false\n\n-- Storage for roles and role members\nlocal roles = {}\nlocal role_members = {}\nlocal role_admins = {}\n\n-- Events (for logging)\nlocal is_log_enabled = true\nlocal events = {}\n\n-- Predefined common roles (similar to OpenZeppelin's common roles)\nAccessControl.ROLES = {\n -- DEFAULT_ADMIN_ROLE acts similar to a \"root\" admin\n DEFAULT_ADMIN = \"DEFAULT_ADMIN_ROLE\",\n MINTER = \"MINTER_ROLE\",\n BURNER = \"BURNER_ROLE\",\n PAUSER = \"PAUSER_ROLE\",\n MANAGER = \"MANAGER_ROLE\",\n MODERATOR = \"MODERATOR_ROLE\",\n UPGRADER = \"UPGRADER_ROLE\",\n ADMIN = \"ADMIN_ROLE\",\n EDITOR = \"EDITOR_ROLE\",\n VIEWER = \"VIEWER_ROLE\"\n}\n\n-- Constants for better maintainability\nAccessControl.ERROR_MESSAGES = {\n NOT_INITIALIZED = \"AccessControl not initialized\",\n INVALID_ACCOUNT = \"Invalid account\",\n INVALID_ROLE = \"Invalid role\",\n ROLE_EXISTS = \"Role already exists\",\n ROLE_NOT_EXISTS = \"Role does not exist\",\n ACCOUNT_HAS_ROLE = \"Account already has role\",\n ACCOUNT_NO_ROLE = \"Account does not have role\",\n MISSING_ROLE = \"AccessControl: account %s is missing role %s\",\n NOT_ADMIN = \"AccessControl: account %s is not admin of role %s\",\n CANNOT_REMOVE_LAST_ADMIN = \"Cannot remove last DEFAULT_ADMIN\"\n}\n\n-- Role logger helper\nlocal function log_role_update(caller, message, role, old_admin_role, new_admin_role)\n if is_log_enabled then\n table.insert(events, {\n type = message,\n role = role,\n oldAdminRole = old_admin_role,\n newAdminRole = new_admin_role,\n caller = caller,\n timestamp = os.time()\n })\n end\nend\n\n-- Account role logger helper\nlocal function log_role_account(caller, message, role, account)\n if is_log_enabled then\n table.insert(events, {\n type = message,\n role = role,\n account = account,\n caller = caller,\n timestamp = os.time()\n })\n end\nend\n\n-- Check if module is initialized\nlocal function check_initialized()\n if not is_initialized then\n return false, AccessControl.ERROR_MESSAGES.NOT_INITIALIZED\n end\n return true, nil\nend\n\n-- Check if a role exists\nfunction AccessControl.role_exists(role)\n return roles[role] == true\nend\n\n-- Validators\nlocal function validate_account(account)\n if not account or type(account) ~= \"string\" or account == \"\" then\n return false, AccessControl.ERROR_MESSAGES.INVALID_ACCOUNT\n end\n return true, nil\nend\n\nlocal function validate_role(role)\n if not role or type(role) ~= \"string\" or role == \"\" then\n return false, AccessControl.ERROR_MESSAGES.INVALID_ROLE\n end\n if not AccessControl.role_exists(role) then\n return false, AccessControl.ERROR_MESSAGES.ROLE_NOT_EXISTS\n end\n return true, nil\nend\n\n-- Combined validation helper\nlocal function validate_inputs(account, role)\n local success, error = check_initialized()\n if not success then return false, error end\n\n success, error = validate_account(account)\n if not success then return false, error end\n\n success, error = validate_role(role)\n if not success then return false, error end\n\n return true, nil\nend\n\n-- Check if an address has a specific role\nfunction AccessControl.has_role(account, role)\n local success, error = validate_inputs(account, role)\n if not success then return false, error end\n\n return role_members[role] and role_members[role][account] == true, nil\nend\n\n-- Get the admin role for a given role\nfunction AccessControl.get_role_admin(role)\n local success, error = check_initialized()\n if not success then return nil, error end\n\n success, error = validate_role(role)\n if not success then return nil, error end\n\n return role_admins[role], nil\nend\n\n-- Get user roles\nfunction AccessControl.get_user_roles(account)\n local success, error = check_initialized()\n if not success then return nil, error end\n\n local user_roles = {}\n for role, exists in pairs(roles) do\n if exists and role_members[role][account] then\n table.insert(user_roles, role)\n end\n end\n\n return user_roles, nil\nend\n\n-- Check if caller can administer a role\nlocal function can_administer_role(caller, role)\n local admin_role, err = AccessControl.get_role_admin(role)\n if err then return false, err end\n\n local has_admin_role, _ = AccessControl.has_role(caller, admin_role)\n local has_default_admin, _ = AccessControl.has_role(caller, AccessControl.ROLES.DEFAULT_ADMIN)\n\n return has_admin_role or has_default_admin,\n string.format(AccessControl.ERROR_MESSAGES.NOT_ADMIN, caller, role)\nend\n\n-- Get all roles\nfunction AccessControl.get_all_roles()\n local success, error = check_initialized()\n if not success then return nil, error end\n\n local all_roles = {}\n for role, exists in pairs(roles) do\n if exists then\n table.insert(all_roles, role)\n end\n end\n return all_roles, nil\nend\n\n-- Get all members of a role\nfunction AccessControl.get_role_members(role)\n local success, error = check_initialized()\n if not success then return nil, error end\n\n success, error = validate_role(role)\n if not success then return nil, error end\n\n local members = {}\n for account, is_member in pairs(role_members[role]) do\n if is_member then table.insert(members, account) end\n end\n\n return members, nil\nend\n\n-- Get the number of members in a role\nfunction AccessControl.get_role_member_count(role)\n local success, error = check_initialized()\n if not success then return 0, error end\n\n success, error = validate_role(role)\n if not success then return 0, error end\n\n local count = 0\n for _, is_member in pairs(role_members[role]) do\n if is_member then count = count + 1 end\n end\n\n return count, nil\nend\n\n-- Initialize the access control system\nfunction AccessControl.init(caller, owner, is_log_disabled)\n if is_initialized then\n return false, \"Already initialized\"\n end\n\n local success, error = validate_account(caller)\n if not success then return false, error end\n\n success, error = validate_account(owner)\n if not success then return false, error end\n\n -- Set up the default admin role\n roles[AccessControl.ROLES.DEFAULT_ADMIN] = true\n role_members[AccessControl.ROLES.DEFAULT_ADMIN] = {}\n role_admins[AccessControl.ROLES.DEFAULT_ADMIN] = AccessControl.ROLES.DEFAULT_ADMIN\n\n -- Grant default admin role to the owner\n role_members[AccessControl.ROLES.DEFAULT_ADMIN][owner] = true\n\n -- Mark module as initialized\n is_initialized = true\n\n -- Configure logging\n if is_log_disabled then\n is_log_enabled = false\n end\n\n log_role_update(caller, \"RoleCreated\", AccessControl.ROLES.DEFAULT_ADMIN, nil, AccessControl.ROLES.DEFAULT_ADMIN)\n log_role_account(caller, \"RoleGranted\", AccessControl.ROLES.DEFAULT_ADMIN, owner)\n\n return true, nil\nend\n\n-- Create a new role\nfunction AccessControl.create_role(caller, role, admin_role)\n admin_role = admin_role or AccessControl.ROLES.DEFAULT_ADMIN\n\n local success, error = validate_inputs(caller, admin_role)\n if not success then return false, error end\n\n -- Check if role already exists\n if AccessControl.role_exists(role) then\n return false, AccessControl.ERROR_MESSAGES.ROLE_EXISTS\n end\n\n -- Check if caller has permission (only admins of admin_role can add \"children\" roles)\n local can_admin, error = can_administer_role(caller, admin_role)\n if not can_admin then return false, error end\n\n roles[role] = true\n role_members[role] = {}\n role_admins[role] = admin_role\n\n -- Log event\n log_role_update(caller, \"RoleCreated\", role, nil, admin_role)\n\n return true, nil\nend\n\n-- Grant a role to an account\nfunction AccessControl.grant_role(caller, role, account)\n local success, error = validate_account(caller)\n if not success then return false, error end\n\n success, error = validate_inputs(account, role)\n if not success then return false, error end\n\n local can_admin, admin_err = can_administer_role(caller, role)\n if not can_admin then return false, admin_err end\n\n local already_has_role, _ = AccessControl.has_role(account, role)\n if already_has_role then\n return true, nil\n end\n\n role_members[role][account] = true\n\n -- Log event\n log_role_account(caller, \"RoleGranted\", role, account)\n\n return true, nil\nend\n\n-- Check if removing this role member would leave no admins\nlocal function would_remove_last_admin(role, account)\n if role ~= AccessControl.ROLES.DEFAULT_ADMIN then\n return false\n end\n\n local count = AccessControl.get_role_member_count(role)\n\n return count == 1 and role_members[role][account] == true\nend\n\n-- Revoke a role from an account\nfunction AccessControl.revoke_role(caller, role, account)\n local success, error = validate_inputs(account, role)\n if not success then return false, error end\n\n local can_admin, err = can_administer_role(caller, role)\n if not can_admin then return false, err end\n\n local has_role, _ = AccessControl.has_role(account, role)\n if not has_role then\n return true, nil\n end\n\n -- Prevent removing the last DEFAULT_ADMIN\n if would_remove_last_admin(role, account) then\n return false, AccessControl.ERROR_MESSAGES.CANNOT_REMOVE_LAST_ADMIN\n end\n\n role_members[role][account] = nil\n\n -- Log event\n log_role_account(caller, \"RoleRevoked\", role, account)\n\n return true, nil\nend\n\n-- Renounce a role (account renounces their own role)\nfunction AccessControl.renounce_role(caller, role)\n local success, error = validate_inputs(caller, role)\n if not success then return false, error end\n\n local has_role, _ = AccessControl.has_role(caller, role)\n if not has_role then\n return false, AccessControl.ERROR_MESSAGES.ACCOUNT_NO_ROLE\n end\n\n -- Prevent renouncing if you're the last DEFAULT_ADMIN\n if would_remove_last_admin(role, caller) then\n return false, AccessControl.ERROR_MESSAGES.CANNOT_REMOVE_LAST_ADMIN\n end\n\n role_members[role][caller] = nil\n\n -- Log event\n log_role_account(caller, \"RoleRenounced\", role, caller)\n\n return true, nil\nend\n\n-- Set a new admin for a role\nfunction AccessControl.set_role_admin(caller, role, admin_role)\n -- can_administer_role already validates caller and role inputs\n local can_admin, err = can_administer_role(caller, role)\n if not can_admin then return false, err end\n\n local success, error = validate_role(admin_role)\n if not success then return false, \"Admin \" .. error end\n\n local old_admin_role = role_admins[role]\n role_admins[role] = admin_role\n\n -- Log event\n log_role_update(caller, \"RoleAdminChanged\", role, old_admin_role, admin_role)\n\n return true, nil\nend\n\n-- Modifier function to check if caller has a specific role\nfunction AccessControl.only_role(caller, role)\n local has_role, error = AccessControl.has_role(caller, role)\n if not has_role then\n return false, error or string.format(AccessControl.ERROR_MESSAGES.MISSING_ROLE, caller or \"unknown\", role)\n end\n return true, nil\nend\n\n-- Modifier function to check if caller is admin of a role\nfunction AccessControl.only_role_admin(caller, role)\n -- can_administer_role already validates account and role\n local can_admin, err = can_administer_role(caller, role)\n return can_admin, err\nend\n\n-- Get all events (for debugging/logging)\nfunction AccessControl.get_events()\n local success, error = check_initialized()\n if not success then return nil, error end\n\n return events, nil\nend\n\n-- Clear events (optional, for memory management)\nfunction AccessControl.clear_events()\n local success, error = check_initialized()\n if not success then return false, error end\n\n events = {}\n return true, nil\nend\n\n-- Helper function to setup common roles\nfunction AccessControl.setup_common_roles(caller)\n local success, error = AccessControl.only_role(caller, AccessControl.ROLES.DEFAULT_ADMIN)\n if not success then return false, error end\n\n -- Create common roles with DEFAULT_ADMIN as their admin\n for _, role in pairs(AccessControl.ROLES) do\n if role ~= AccessControl.ROLES.DEFAULT_ADMIN then\n AccessControl.create_role(caller, role, AccessControl.ROLES.DEFAULT_ADMIN)\n end\n end\n\n return true, nil\nend\n\n-- Additional utility functions\n\n-- Check if the system is initialized\nfunction AccessControl.is_initialized()\n return is_initialized\nend\n\n-- Get system status\nfunction AccessControl.get_status()\n return {\n initialized = is_initialized,\n logging_enabled = is_log_enabled,\n total_roles = #AccessControl.get_all_roles() or 0,\n total_events = #events\n }\nend\n\n-- Bulk operations for efficiency\nfunction AccessControl.bulk_grant_role(caller, role, accounts)\n local success, error = check_initialized()\n if not success then return false, error end\n\n if not accounts or type(accounts) ~= \"table\" then\n return false, \"Accounts must be a table\"\n end\n\n local results = {}\n for _, account in ipairs(accounts) do\n local result, err = AccessControl.grant_role(caller, role, account)\n table.insert(results, { account = account, success = result, error = err })\n end\n\n return true, results\nend\n\nreturn AccessControl";
//# sourceMappingURL=access-control-contract.d.ts.map