mirror of
https://github.com/status-im/snt-gas-relay.git
synced 2025-02-27 21:20:28 +00:00
remove loops from recovery by add salt to keys storage pointer
This commit is contained in:
parent
6f52b6cde8
commit
5b7124fc57
@ -10,15 +10,15 @@ import "../common/MessageSigned.sol";
|
||||
*/
|
||||
contract Identity is ERC725, ERC735, MessageSigned {
|
||||
|
||||
uint256 public nonce;
|
||||
uint256 public nonce;
|
||||
address public recoveryContract;
|
||||
bytes32 recoveryNewKey;
|
||||
uint256 salt;
|
||||
|
||||
mapping (bytes32 => uint256) indexes;
|
||||
|
||||
mapping (bytes32 => Key) keys;
|
||||
mapping (bytes32 => bool) isKeyPurpose;
|
||||
mapping (uint256 => bytes32[]) keysByPurpose;
|
||||
mapping (bytes32 => bytes32[]) keysByPurpose;
|
||||
|
||||
mapping (uint256 => Transaction) pendingTx;
|
||||
mapping (uint256 => uint256) purposeThreshold;
|
||||
@ -72,9 +72,10 @@ contract Identity is ERC725, ERC735, MessageSigned {
|
||||
recoverAddress(
|
||||
getSignHash(_messageHash),
|
||||
_signature
|
||||
)
|
||||
)
|
||||
);
|
||||
),
|
||||
salt
|
||||
)
|
||||
);
|
||||
_;
|
||||
}
|
||||
|
||||
@ -218,7 +219,7 @@ contract Identity is ERC725, ERC735, MessageSigned {
|
||||
managementOnly
|
||||
returns (bool success)
|
||||
{
|
||||
_addKey(_key, _purpose, _type);
|
||||
_addKey(_key, _purpose, _type, salt);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -239,8 +240,8 @@ contract Identity is ERC725, ERC735, MessageSigned {
|
||||
managementOnly
|
||||
returns (bool success)
|
||||
{
|
||||
_addKey(_recoveryNewKey, _purpose, _newType);
|
||||
_removeKey(_oldKey, _purpose);
|
||||
_addKey(_recoveryNewKey, _purpose, _newType, salt);
|
||||
_removeKey(_oldKey, _purpose, salt);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -257,7 +258,7 @@ contract Identity is ERC725, ERC735, MessageSigned {
|
||||
managementOnly
|
||||
returns (bool success)
|
||||
{
|
||||
_removeKey(_key, _purpose);
|
||||
_removeKey(_key, _purpose, salt);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -274,7 +275,7 @@ contract Identity is ERC725, ERC735, MessageSigned {
|
||||
managementOnly
|
||||
{
|
||||
require(_minimumApprovals > 0);
|
||||
require(_minimumApprovals <= keysByPurpose[_purpose].length);
|
||||
require(_minimumApprovals <= keysByPurpose[keccak256(_purpose, salt)].length);
|
||||
purposeThreshold[_purpose] = _minimumApprovals;
|
||||
}
|
||||
|
||||
@ -358,54 +359,19 @@ contract Identity is ERC725, ERC735, MessageSigned {
|
||||
////////////////
|
||||
|
||||
/**
|
||||
* @notice Add `_recoveryNewKey` as ACTION_KEY and MANAGEMENT_KEY and change
|
||||
* purposeThreshold of ACTION_KEY and _MANAGEMENT_KEY to all keys in their purpose.
|
||||
* enables `processRecoveryReset(uint256)` to wipe all keys but `_recoveryNewKey`.
|
||||
* @notice Increase salt for hashing storage pointer of keys and add `_recoveryNewKey`
|
||||
* @param _recoveryNewKey new key being defined
|
||||
*/
|
||||
function recoveryReset(bytes32 _recoveryNewKey)
|
||||
public
|
||||
recoveryOnly
|
||||
{
|
||||
recoveryNewKey = _recoveryNewKey;
|
||||
_addKey(_recoveryNewKey, MANAGEMENT_KEY, 0); //add _newRecoveryKey in last position
|
||||
_removeKey(keysByPurpose[MANAGEMENT_KEY][0], MANAGEMENT_KEY);//replace first element with last
|
||||
purposeThreshold[MANAGEMENT_KEY] = keysByPurpose[MANAGEMENT_KEY].length; //"lock" management
|
||||
purposeThreshold[ACTION_KEY] = keysByPurpose[ACTION_KEY].length; //"lock" action
|
||||
salt++;
|
||||
_addKey(_recoveryNewKey, MANAGEMENT_KEY, 0, salt);
|
||||
_addKey(_recoveryNewKey, ACTION_KEY, 0, salt);
|
||||
purposeThreshold[MANAGEMENT_KEY] = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Removes all management keys, except recoveryNewKey defined by `recoveryReset(bytes32)`
|
||||
* @param _limit how much management keys to remove in this interaction, 0 = all.
|
||||
*/
|
||||
function processRecoveryReset(uint256 _limit)
|
||||
public
|
||||
{
|
||||
bytes32 _recoveryNewKey = recoveryNewKey;
|
||||
require(_recoveryNewKey != 0);
|
||||
uint256 limit = _limit;
|
||||
bytes32[] memory managers = keysByPurpose[MANAGEMENT_KEY];
|
||||
uint256 totalManagers = managers.length;
|
||||
if (limit == 0) {
|
||||
limit = totalManagers;
|
||||
}
|
||||
keysByPurpose[MANAGEMENT_KEY].length -= limit-1; //trim off purposes being deleted
|
||||
for (uint256 i = limit; i > 0; i--) { //go backwards to avoid indexes replacement
|
||||
bytes32 _key = managers[i - 1];
|
||||
if (_key != _recoveryNewKey) {
|
||||
bytes32 keyPurposeHash = keccak256(_key, MANAGEMENT_KEY);
|
||||
delete isKeyPurpose[keyPurposeHash];
|
||||
delete indexes[keyPurposeHash];
|
||||
delete keys[_key];
|
||||
totalManagers--;
|
||||
}
|
||||
}
|
||||
if (totalManagers == 1) {
|
||||
purposeThreshold[MANAGEMENT_KEY] = 1; // "unlock" management
|
||||
delete recoveryNewKey;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////
|
||||
// Public Views
|
||||
////////////////
|
||||
@ -418,7 +384,7 @@ contract Identity is ERC725, ERC735, MessageSigned {
|
||||
view
|
||||
returns(uint256[] purposes, uint256 keyType, bytes32 key)
|
||||
{
|
||||
Key storage myKey = keys[_key];
|
||||
Key storage myKey = keys[keccak256(_key, salt)];
|
||||
return (myKey.purposes, myKey.keyType, myKey.key);
|
||||
}
|
||||
|
||||
@ -435,7 +401,7 @@ contract Identity is ERC725, ERC735, MessageSigned {
|
||||
view
|
||||
returns(uint256[] purpose)
|
||||
{
|
||||
return keys[_key].purposes;
|
||||
return keys[keccak256(_key, salt)].purposes;
|
||||
}
|
||||
|
||||
function getKeysByPurpose(uint256 _purpose)
|
||||
@ -443,7 +409,7 @@ contract Identity is ERC725, ERC735, MessageSigned {
|
||||
view
|
||||
returns(bytes32[])
|
||||
{
|
||||
return keysByPurpose[_purpose];
|
||||
return keysByPurpose[keccak256(_purpose, salt)];
|
||||
}
|
||||
|
||||
function getClaim(bytes32 _claimId)
|
||||
@ -477,10 +443,11 @@ contract Identity is ERC725, ERC735, MessageSigned {
|
||||
function _constructIdentity(bytes32 _managerKey)
|
||||
internal
|
||||
{
|
||||
require(keysByPurpose[MANAGEMENT_KEY].length == 0);
|
||||
uint256 _salt = salt;
|
||||
require(keysByPurpose[keccak256(MANAGEMENT_KEY, _salt)].length == 0);
|
||||
require(purposeThreshold[MANAGEMENT_KEY] == 0);
|
||||
_addKey(_managerKey, MANAGEMENT_KEY, 0);
|
||||
_addKey(_managerKey, ACTION_KEY, 0);
|
||||
_addKey(_managerKey, MANAGEMENT_KEY, 0, _salt);
|
||||
_addKey(_managerKey, ACTION_KEY, 0, _salt);
|
||||
|
||||
purposeThreshold[MANAGEMENT_KEY] = 1;
|
||||
purposeThreshold[ACTION_KEY] = 1;
|
||||
@ -589,23 +556,27 @@ contract Identity is ERC725, ERC735, MessageSigned {
|
||||
function _addKey(
|
||||
bytes32 _key,
|
||||
uint256 _purpose,
|
||||
uint256 _type
|
||||
uint256 _type,
|
||||
uint256 _salt
|
||||
)
|
||||
private
|
||||
{
|
||||
require(_purpose > 0);
|
||||
bytes32 keyPurposeHash = keccak256(_key, _purpose);
|
||||
|
||||
require(!isKeyPurpose[keyPurposeHash]);
|
||||
isKeyPurpose[keyPurposeHash] = true;
|
||||
indexes[keyPurposeHash] = keysByPurpose[_purpose].push(_key) - 1;
|
||||
if (keys[_key].key == 0) {
|
||||
uint256[] memory purposes = new uint256[](_purpose);
|
||||
keys[_key] = Key(purposes,_type,_key);
|
||||
keys[_key].key == _key;
|
||||
keys[_key].keyType == _type;
|
||||
bytes32 keySaltedHash = keccak256(_key, _salt); //key storage pointer
|
||||
bytes32 saltedKeyPurposeHash = keccak256(keySaltedHash, _purpose); // accounts by purpose hash element index pointer
|
||||
|
||||
require(!isKeyPurpose[saltedKeyPurposeHash]); //cannot add a key already added
|
||||
isKeyPurpose[saltedKeyPurposeHash] = true; //set authorization
|
||||
uint256 keyElementIndex = keysByPurpose[saltedKeyPurposeHash].push(_key) - 1; //add key to list by purpose
|
||||
indexes[saltedKeyPurposeHash] = keyElementIndex; //save index of key in list by purpose
|
||||
if (keys[keySaltedHash].key == 0) { //is a new key
|
||||
uint256[] memory purposes = new uint256[](_purpose); //create new array with first purpose
|
||||
keys[keySaltedHash] = Key(purposes,_type,_key); //add new key
|
||||
} else {
|
||||
indexes[keccak256(keyPurposeHash)] = keys[_key].purposes.push(_purpose) - 1;
|
||||
uint256 addedPurposeElementIndex = keys[keySaltedHash].purposes.push(_purpose) - 1; //add purpose to key
|
||||
bytes32 keyPurposeSaltedHash = keccak256(_key, _purpose, _salt); //index of purpose in key pointer
|
||||
indexes[keyPurposeSaltedHash] = addedPurposeElementIndex; //save index
|
||||
}
|
||||
|
||||
emit KeyAdded(_key, _purpose, _type);
|
||||
@ -614,48 +585,51 @@ contract Identity is ERC725, ERC735, MessageSigned {
|
||||
|
||||
function _removeKey(
|
||||
bytes32 _key,
|
||||
uint256 _purpose
|
||||
uint256 _purpose,
|
||||
uint256 _salt
|
||||
)
|
||||
private
|
||||
{
|
||||
//forbidden to remove last management key
|
||||
bytes32 purposeSaltedHash = keccak256(_purpose, _salt); // salted accounts by purpose array index pointer
|
||||
// forbidden to remove last management key
|
||||
if (_purpose == MANAGEMENT_KEY) {
|
||||
require(keysByPurpose[MANAGEMENT_KEY].length > purposeThreshold[MANAGEMENT_KEY]);
|
||||
require(keysByPurpose[purposeSaltedHash].length > purposeThreshold[MANAGEMENT_KEY]);
|
||||
}
|
||||
|
||||
//require isKeyPurpose mapping and remove it
|
||||
bytes32 keyPurposeHash = keccak256(_key, _purpose);
|
||||
require(isKeyPurpose[keyPurposeHash]);
|
||||
delete isKeyPurpose[keyPurposeHash];
|
||||
bytes32 keySaltedHash = keccak256(_key, _salt); // key storage pointer
|
||||
bytes32 saltedKeyPurposeHash = keccak256(keySaltedHash, _purpose); // accounts by purpose hash element index pointer
|
||||
require(isKeyPurpose[saltedKeyPurposeHash]); //not possible to remove what not exists
|
||||
delete isKeyPurpose[saltedKeyPurposeHash]; //remove authorization
|
||||
|
||||
//remove keys by purpose array element
|
||||
uint256 removedIndex = indexes[keyPurposeHash];
|
||||
delete indexes[keyPurposeHash];
|
||||
uint256 replacerIndex = keysByPurpose[_purpose].length - 1; // replacer is last element
|
||||
if(removedIndex != replacerIndex) {
|
||||
bytes32 replacerKey = keysByPurpose[_purpose][replacerIndex];
|
||||
keysByPurpose[_purpose][removedIndex] = replacerKey; //overwrite removed index by replacer
|
||||
indexes[keccak256(replacerKey, _purpose)] = removedIndex; //update index of replacer
|
||||
// remove keys by purpose array key element
|
||||
uint256 removedKeyIndex = indexes[saltedKeyPurposeHash]; // read old key element index
|
||||
delete indexes[saltedKeyPurposeHash]; // delete key index
|
||||
|
||||
uint256 replacerKeyIndex = keysByPurpose[purposeSaltedHash].length - 1; // replacer is last element
|
||||
if (removedKeyIndex != replacerKeyIndex) { // deleted not the last element, replace deleted by last element
|
||||
bytes32 replacerKey = keysByPurpose[purposeSaltedHash][replacerKeyIndex]; // get replacer key
|
||||
keysByPurpose[purposeSaltedHash][removedKeyIndex] = replacerKey; // overwrite removed index by replacer
|
||||
indexes[keccak256(keccak256(replacerKey, _salt), _purpose)] = removedKeyIndex; // update saltedKeyPurposeHash index of replacer
|
||||
}
|
||||
keysByPurpose[_purpose].length--; //remove last element
|
||||
keysByPurpose[purposeSaltedHash].length--; // remove last element
|
||||
|
||||
//remove key purposes array element
|
||||
Key storage myKey = keys[_key];
|
||||
uint256 _type = myKey.keyType;
|
||||
replacerIndex = myKey.purposes.length;
|
||||
if (replacerIndex > 1) {
|
||||
replacerIndex--;
|
||||
bytes32 keyPurposeHashHash = keccak256(keyPurposeHash);
|
||||
removedIndex = indexes[keyPurposeHashHash];
|
||||
delete indexes[keyPurposeHashHash];
|
||||
if(removedIndex != replacerIndex) {
|
||||
uint256 replacerPurpose = myKey.purposes[replacerIndex];
|
||||
myKey.purposes[removedIndex] = replacerPurpose;
|
||||
indexes[keccak256(keccak256(_key, replacerPurpose))] = removedIndex;
|
||||
//remove key purposes array purpose element
|
||||
Key storage myKey = keys[keySaltedHash]; //load Key storage pointer
|
||||
uint256 _type = myKey.keyType; //save type for case key deleted
|
||||
uint256 replacerPurposeIndex = myKey.purposes.length; //load amount of purposes
|
||||
bytes32 keyPurposeSaltedHash = keccak256(_key, _purpose, _salt); //account purpose array element index
|
||||
uint256 removedPurposeIndex = indexes[keyPurposeSaltedHash]; //read old index
|
||||
delete indexes[keyPurposeSaltedHash]; //delete key's purpose index
|
||||
if (replacerPurposeIndex > 1) { //is not the last key
|
||||
replacerPurposeIndex--; //move to last element pos
|
||||
if(removedPurposeIndex != replacerPurposeIndex) { //removed element is not last element
|
||||
uint256 replacerPurpose = myKey.purposes[replacerPurposeIndex]; //take last element
|
||||
myKey.purposes[removedPurposeIndex] = replacerPurpose; //replace removed element with replacer element
|
||||
indexes[keccak256(_key, replacerPurpose, _salt)] = removedPurposeIndex; //update index
|
||||
}
|
||||
myKey.purposes.length--;
|
||||
} else {
|
||||
delete keys[_key];
|
||||
myKey.purposes.length--; //remove last element
|
||||
} else { //is the last purpose
|
||||
delete keys[keySaltedHash]; //drop this Key
|
||||
}
|
||||
|
||||
emit KeyRemoved(_key, _purpose, _type);
|
||||
|
Loading…
x
Reference in New Issue
Block a user