Skip to content

Commit

Permalink
Implement Security Policy Plugin Management
Browse files Browse the repository at this point in the history
  • Loading branch information
ankurdubey521 committed Oct 11, 2023
1 parent 5ff3e88 commit a72ec6b
Show file tree
Hide file tree
Showing 3 changed files with 259 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {ISecurityPolicyPlugin} from "./ISecurityPolicyPlugin.sol";

address constant SENTINEL_MODULE_ADDRESS = address(0x1);

/// @title Security Policy Manager Plugin
/// @author @ankurdubey521
/// @dev Execution Phase Plugin responsible for enforcing security policies during plugin installation on the smart contract wallet
interface ISecurityPolicyManagerPlugin {
event SecurityPolicyEnabled(address indexed scw, address indexed policy);
event SecurityPolicyDisabled(address indexed scw, address indexed policy);

error SecurityPolicyAlreadyEnabled(address policy);
error SecurityPolicyAlreadyDisabled(address policy);
error InvalidSecurityPolicyAddress(address policy);
error InvalidPointerAddress(address pointer);
error EmptyPolicyList();

/// @dev Enables the security policies for the smart contract wallet. Used during the setup process.
/// @param _policy The security policy to be enabled
function enableSecurityPolicy(ISecurityPolicyPlugin _policy) external;

/// @dev Enables the security policies for the smart contract wallet. Used during the setup process.
/// @param _policies The security policies to be enabled
function enableSecurityPolicies(
ISecurityPolicyPlugin[] calldata _policies
) external;

/// @dev Disables the security policy for the smart contract wallet.
/// @param _policy The security policy to be disabled.
/// @param _pointer The address of the security policy preceeding _policy in the list of enabled modules.
function disableSecurityPolicy(
ISecurityPolicyPlugin _policy,
ISecurityPolicyPlugin _pointer
) external;

/// @dev Disables the security policies for the smart contract wallet.
/// @param _start The first iterm in the list to be disabled.
/// @param _end The last iterm in the list to be disabled.
/// @param _pointer The address of the security policy preceeding _start in the list of enabled modules.
function disableSecurityPoliciesRange(
ISecurityPolicyPlugin _start,
ISecurityPolicyPlugin _end,
ISecurityPolicyPlugin _pointer
) external;

/// @dev Queries the registry and checks if the module is valid and enables the module.
/// @param _setupContract The address of the module contract
/// @param _setupData The data to be passed to the module contract during setup
function checkSetupAndEnableModule(
address _setupContract,
bytes calldata _setupData
) external returns (address module);

/// @dev Returns the security policy for the smart contract wallet.
/// @param _scw The address of the smart contract wallet
/// @return SecurityPolicy The security policy of the smart contract wallet
function securityPolicies(
address _scw
) external view returns (ISecurityPolicyPlugin[] memory);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/// @title Security Policy Plugin
/// @author @ankurdubey521
/// @dev A security policy plugin is a plugin which enforce arbitrary checks and condition during plugin installation on the smart contract wallet
interface ISecurityPolicyPlugin {
/// @dev Validates the security policy for the plugin to be installed, based on the parameters
/// set in the security policy of the smart contract wallet.
/// @param _scw The address of the smart contract wallet
/// @param _plugin The address of the plugin to be installed
function validateSecurityPolicy(
address _scw,
address _plugin
) external view;
}
180 changes: 180 additions & 0 deletions contracts/smart-account/modules/SecurityPolicyManagerPlugin.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {ISecurityPolicyManagerPlugin, ISecurityPolicyPlugin, SENTINEL_MODULE_ADDRESS} from "contracts/smart-account/interfaces/modules/ISecurityPolicyManagerPlugin.sol";

contract SecurityPolicyManagerPlugin is ISecurityPolicyManagerPlugin {
mapping(address => mapping(address => address))
internal enabledSecurityPoliciesLinkedList;

/// @inheritdoc ISecurityPolicyManagerPlugin
function enableSecurityPolicy(
ISecurityPolicyPlugin _policy
) external override {
if (
_policy == ISecurityPolicyPlugin(address(0x0)) ||
_policy == ISecurityPolicyPlugin(SENTINEL_MODULE_ADDRESS)
) {
revert InvalidSecurityPolicyAddress(address(_policy));
}

mapping(address => address)
storage enabledSecurityPolicies = enabledSecurityPoliciesLinkedList[
msg.sender
];

if (enabledSecurityPolicies[address(_policy)] != address(0x0)) {
revert SecurityPolicyAlreadyEnabled(address(_policy));
}

enabledSecurityPolicies[address(_policy)] = enabledSecurityPolicies[
SENTINEL_MODULE_ADDRESS
];
enabledSecurityPolicies[SENTINEL_MODULE_ADDRESS] = address(_policy);

emit SecurityPolicyEnabled(msg.sender, address(_policy));
}

/// @inheritdoc ISecurityPolicyManagerPlugin
function enableSecurityPolicies(
ISecurityPolicyPlugin[] calldata _policies
) external override {
mapping(address => address)
storage enabledSecurityPolicies = enabledSecurityPoliciesLinkedList[
msg.sender
];

// TODO: Verify if this reduces gas
uint256 length = _policies.length;

if (length == 0) {
revert EmptyPolicyList();
}

address head = enabledSecurityPolicies[SENTINEL_MODULE_ADDRESS];

for (uint256 i; i < length; ) {
address policy = address(_policies[i]);

if (policy == address(0x0) || policy == SENTINEL_MODULE_ADDRESS) {
revert InvalidSecurityPolicyAddress(policy);
}

if (enabledSecurityPolicies[address(policy)] != address(0x0)) {
revert SecurityPolicyAlreadyEnabled(address(policy));
}

enabledSecurityPolicies[policy] = head;
head = policy;

emit SecurityPolicyEnabled(msg.sender, policy);

unchecked {
++i;
}
}

enabledSecurityPolicies[SENTINEL_MODULE_ADDRESS] = head;
}

/// @inheritdoc ISecurityPolicyManagerPlugin
function disableSecurityPolicy(
ISecurityPolicyPlugin _policy,
ISecurityPolicyPlugin _pointer
) external override {
if (
_policy == ISecurityPolicyPlugin(address(0x0)) ||
_policy == ISecurityPolicyPlugin(SENTINEL_MODULE_ADDRESS)
) {
revert InvalidSecurityPolicyAddress(address(_policy));
}

mapping(address => address)
storage enabledSecurityPolicies = enabledSecurityPoliciesLinkedList[
msg.sender
];

if (enabledSecurityPolicies[address(_policy)] == address(0x0)) {
revert SecurityPolicyAlreadyDisabled(address(_policy));
}

if (enabledSecurityPolicies[address(_pointer)] != address(_policy)) {
revert InvalidPointerAddress(address(_pointer));
}

enabledSecurityPolicies[address(_pointer)] = enabledSecurityPolicies[
address(_policy)
];
delete enabledSecurityPolicies[address(_policy)];

emit SecurityPolicyDisabled(msg.sender, address(_policy));
}

/// @inheritdoc ISecurityPolicyManagerPlugin
function disableSecurityPoliciesRange(
ISecurityPolicyPlugin _start,
ISecurityPolicyPlugin _end,
ISecurityPolicyPlugin _pointer
) external override {
mapping(address => address)
storage enabledSecurityPolicies = enabledSecurityPoliciesLinkedList[
msg.sender
];

if (enabledSecurityPolicies[address(_pointer)] != address(_start)) {
revert InvalidPointerAddress(address(_pointer));
}

if (
_start == ISecurityPolicyPlugin(address(0x0)) ||
_start == ISecurityPolicyPlugin(SENTINEL_MODULE_ADDRESS)
) {
revert InvalidSecurityPolicyAddress(address(_start));
}

if (
_end == ISecurityPolicyPlugin(address(0x0)) ||
_end == ISecurityPolicyPlugin(SENTINEL_MODULE_ADDRESS)
) {
revert InvalidSecurityPolicyAddress(address(_end));
}

enabledSecurityPolicies[address(_pointer)] = enabledSecurityPolicies[
address(_end)
];

bool endFound = false;
address current = address(_start);
while (current != address(_end) || current != SENTINEL_MODULE_ADDRESS) {
if (current == address(_end)) {
endFound = true;
}

address next = enabledSecurityPolicies[current];
delete enabledSecurityPolicies[current];

emit SecurityPolicyDisabled(msg.sender, current);

current = next;
}

if (!endFound) {
revert InvalidSecurityPolicyAddress(address(_end));
}
}

/// @inheritdoc ISecurityPolicyManagerPlugin
function checkSetupAndEnableModule(
address,
bytes calldata
) external override returns (address) {
revert("Not implemented");
}

/// @inheritdoc ISecurityPolicyManagerPlugin
function securityPolicies(
address
) external view override returns (ISecurityPolicyPlugin[] memory) {
revert("Not implemented");
}
}

0 comments on commit a72ec6b

Please sign in to comment.