-
Notifications
You must be signed in to change notification settings - Fork 83
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement Security Policy Plugin Management
- Loading branch information
1 parent
5ff3e88
commit a72ec6b
Showing
3 changed files
with
259 additions
and
0 deletions.
There are no files selected for viewing
63 changes: 63 additions & 0 deletions
63
contracts/smart-account/interfaces/modules/ISecurityPolicyManagerPlugin.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} |
16 changes: 16 additions & 0 deletions
16
contracts/smart-account/interfaces/modules/ISecurityPolicyPlugin.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
180
contracts/smart-account/modules/SecurityPolicyManagerPlugin.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"); | ||
} | ||
} |