Skip to content

Commit

Permalink
Update UserOverrideableDKIMRegistry.sol
Browse files Browse the repository at this point in the history
  • Loading branch information
SoraSuegami committed Jun 3, 2024
1 parent 8cbd89c commit 08249d6
Showing 1 changed file with 202 additions and 63 deletions.
265 changes: 202 additions & 63 deletions packages/contracts/UserOverrideableDKIMRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ pragma solidity ^0.8.0;

import "@openzeppelin/contracts/access/Ownable.sol";
import "./interfaces/IDKIMRegistry.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol";
import "@openzeppelin/contracts/utils/Strings.sol";

/**
A Registry that store the hash(dkim_public_key) for each domain
Expand All @@ -13,7 +17,8 @@ import "./interfaces/IDKIMRegistry.sol";
Input is DKIM pub key split into 17 chunks of 121 bits. You can use `helpers` package to fetch/split DKIM keys
*/
contract UserOverrideableDKIMRegistry is IDKIMRegistry, Ownable {
constructor(address _owner) Ownable(_owner) {}
using Strings for *;
using ECDSA for *;

event DKIMPublicKeyHashRegistered(
string domainName,
Expand All @@ -22,6 +27,9 @@ contract UserOverrideableDKIMRegistry is IDKIMRegistry, Ownable {
);
event DKIMPublicKeyHashRevoked(bytes32 publicKeyHash, address register);

// Main authorizer address.
address public mainAuthorizer;

// Mapping from domain name to DKIM public key hash
mapping(string => mapping(bytes32 => mapping(address => bool)))
public dkimPublicKeyHashes;
Expand All @@ -30,100 +38,231 @@ contract UserOverrideableDKIMRegistry is IDKIMRegistry, Ownable {
mapping(bytes32 => mapping(address => bool))
public revokedDKIMPublicKeyHashes;

function _stringEq(
string memory a,
string memory b
) internal pure returns (bool) {
return keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b));
string public constant SET_PREFIX = "SET:";
string public constant REVOKE_PREFIX = "REVOKE:";

constructor(address _owner, address _mainAuthorizer) Ownable(_owner) {
mainAuthorizer = _mainAuthorizer;
}

function isDKIMPublicKeyHashValid(
string memory domainName,
bytes32 publicKeyHash
) public view returns (bool) {
if (
revokedDKIMPublicKeyHashes[publicKeyHash][address(0)] ||
revokedDKIMPublicKeyHashes[publicKeyHash][msg.sender]
) {
return false;
}

if (dkimPublicKeyHashes[domainName][publicKeyHash][address(0)]) {
return true;
}
return isDKIMPublicKeyHashValid(domainName, publicKeyHash, msg.sender);
}

if (dkimPublicKeyHashes[domainName][publicKeyHash][msg.sender]) {
function isDKIMPublicKeyHashValid(
string memory domainName,
bytes32 publicKeyHash,
address user
) public view returns (bool) {
require(bytes(domainName).length > 0, "domain name cannot be zero");
require(publicKeyHash != bytes32(0), "public key hash cannot be zero");
require(user != address(0), "user address cannot be zero");
uint256 revokeThreshold = _computeRevokeThreshold(publicKeyHash, user);
uint256 setThreshold = _computeSetThreshold(
domainName,
publicKeyHash,
user
);
if (revokeThreshold >= 1) {
return false;
} else if (setThreshold < 2) {
return false;
} else {
return true;
}

return false;
}

/**
* @notice Sets the DKIM public key hash for a given domain.
* @dev This function allows the owner to set a DKIM public key hash for all users, or an individual user to set it for themselves.
* @param domainName The domain name for which the DKIM public key hash is being set.
* @param publicKeyHash The hash of the DKIM public key to be set.
* @param individual A boolean indicating whether the hash is being set for an individual user (true) or for all users (false).
* @custom:require Only the owner can set the DKIM public key hash for all users when `individual` is false.
* @custom:require The public key hash must not be revoked.
* @custom:event DKIMPublicKeyHashRegistered Emitted when a DKIM public key hash is successfully set.
*/
// /**
// * @notice Sets the DKIM public key hash for a given domain.
// * @dev This function allows the owner to set a DKIM public key hash for all users, or an individual user to set it for themselves.
// * @param domainName The domain name for which the DKIM public key hash is being set.
// * @param publicKeyHash The hash of the DKIM public key to be set.
// * @param individual A boolean indicating whether the hash is being set for an individual user (true) or for all users (false).
// * @custom:require Only the owner can set the DKIM public key hash for all users when `individual` is false.
// * @custom:require The public key hash must not be revoked.
// * @custom:event DKIMPublicKeyHashRegistered Emitted when a DKIM public key hash is successfully set.
// */
function setDKIMPublicKeyHash(
string memory domainName,
bytes32 publicKeyHash,
bool individual
address authorizer,
bytes memory signature
) public {
address register = msg.sender;
if (!individual) {
require(
msg.sender == owner(),
"only owner can set DKIM public key hash for all users"
);
register = address(0);
}
require(bytes(domainName).length > 0, "domain name cannot be zero");
require(publicKeyHash != bytes32(0), "public key hash cannot be zero");
require(authorizer != address(0), "authorizer address cannot be zero");
require(
!revokedDKIMPublicKeyHashes[publicKeyHash][register],
"cannot set revoked pubkey"
revokedDKIMPublicKeyHashes[publicKeyHash][authorizer] == false,
"public key hash is already revoked"
);
if (msg.sender != authorizer) {
string memory signedMsg = computeSignedMsg(
SET_PREFIX,
domainName,
publicKeyHash
);
bytes32 digest = MessageHashUtils.toEthSignedMessageHash(
bytes(signedMsg)
);
if (authorizer.code.length > 0) {
require(
IERC1271(authorizer).isValidSignature(digest, signature) ==
0x1626ba7e,
"invalid eip1271 signature"
);
} else {
address recoveredSigner = digest.recover(signature);
require(
recoveredSigner == authorizer,
"invalid ecdsa signature"
);
}
}

dkimPublicKeyHashes[domainName][publicKeyHash][register] = true;
dkimPublicKeyHashes[domainName][publicKeyHash][authorizer] = true;

emit DKIMPublicKeyHashRegistered(domainName, publicKeyHash, register);
emit DKIMPublicKeyHashRegistered(domainName, publicKeyHash, authorizer);
}

function setDKIMPublicKeyHashes(
string memory domainName,
string[] memory domainNames,
bytes32[] memory publicKeyHashes,
bool individual
address[] memory authorizers,
bytes[] memory signatures
) public {
for (uint256 i = 0; i < publicKeyHashes.length; i++) {
setDKIMPublicKeyHash(domainName, publicKeyHashes[i], individual);
require(
domainNames.length == publicKeyHashes.length,
"invalid publicKeyHashes length"
);
require(
domainNames.length == authorizers.length,
"invalid authorizers length"
);
require(
domainNames.length == signatures.length,
"invalid signatures length"
);
for (uint256 i = 0; i < domainNames.length; i++) {
setDKIMPublicKeyHash(
domainNames[i],
publicKeyHashes[i],
authorizers[i],
signatures[i]
);
}
}

/**
* @notice Revokes a DKIM public key hash.
* @dev This function allows the owner to revoke a DKIM public key hash for all users, or an individual user to revoke it for themselves.
* @param publicKeyHash The hash of the DKIM public key to be revoked.
* @param individual A boolean indicating whether the hash is being revoked for an individual user (true) or for all users (false).
* @custom:require Only the owner can revoke the DKIM public key hash for all users when `individual` is false.
* @custom:event DKIMPublicKeyHashRevoked Emitted when a DKIM public key hash is successfully revoked.
*/
// /**
// * @notice Revokes a DKIM public key hash.
// * @dev This function allows the owner to revoke a DKIM public key hash for all users, or an individual user to revoke it for themselves.
// * @param publicKeyHash The hash of the DKIM public key to be revoked.
// * @param individual A boolean indicating whether the hash is being revoked for an individual user (true) or for all users (false).
// * @custom:require Only the owner can revoke the DKIM public key hash for all users when `individual` is false.
// * @custom:event DKIMPublicKeyHashRevoked Emitted when a DKIM public key hash is successfully revoked.
// */
function revokeDKIMPublicKeyHash(
string memory domainName,
bytes32 publicKeyHash,
bool individual
address authorizer,
bytes memory signature
) public {
address register = msg.sender;
if (!individual) {
require(
msg.sender == owner(),
"only owner can revoke DKIM public key hash for all users"
require(bytes(domainName).length > 0, "domain name cannot be zero");
require(publicKeyHash != bytes32(0), "public key hash cannot be zero");
require(authorizer != address(0), "authorizer address cannot be zero");
require(
revokedDKIMPublicKeyHashes[publicKeyHash][authorizer] == false,
"public key hash is already revoked"
);
if (msg.sender != authorizer) {
string memory signedMsg = computeSignedMsg(
REVOKE_PREFIX,
domainName,
publicKeyHash
);
bytes32 digest = MessageHashUtils.toEthSignedMessageHash(
bytes(signedMsg)
);
if (authorizer.code.length > 0) {
require(
IERC1271(authorizer).isValidSignature(digest, signature) ==
0x1626ba7e,
"invalid eip1271 signature"
);
} else {
address recoveredSigner = digest.recover(signature);
require(
recoveredSigner == authorizer,
"invalid ecdsa signature"
);
}
}
revokedDKIMPublicKeyHashes[publicKeyHash][authorizer] = true;

emit DKIMPublicKeyHashRevoked(publicKeyHash, authorizer);
}

// / @notice Computes a signed message string for setting or revoking a DKIM public key hash.
// / @param prefix The operation prefix (SET: or REVOKE:).
// / @param selector The selector associated with the DKIM public key.
// / @param domainName The domain name related to the operation.
// / @param publicKeyHash The DKIM public key hash involved in the operation.
// / @return string The computed signed message.
// / @dev This function is used internally to generate the message that needs to be signed for setting or revoking a public key hash.
function computeSignedMsg(
string memory prefix,
string memory domainName,
bytes32 publicKeyHash
) public pure returns (string memory) {
return
string.concat(
prefix,
";domain=",
domainName,
";public_key_hash=",
uint256(publicKeyHash).toHexString(),
";"
);
register = address(0);
}

function _computeSetThreshold(
string memory domainName,
bytes32 publicKeyHash,
address user
) private view returns (uint256) {
uint256 threshold = 0;
if (
dkimPublicKeyHashes[domainName][publicKeyHash][mainAuthorizer] ==
true
) {
threshold += 1;
}
if (dkimPublicKeyHashes[domainName][publicKeyHash][user] == true) {
threshold += 2;
}
return threshold;
}

function _computeRevokeThreshold(
bytes32 publicKeyHash,
address user
) private view returns (uint256) {
uint256 threshold = 0;
if (revokedDKIMPublicKeyHashes[publicKeyHash][mainAuthorizer] == true) {
threshold += 1;
}
if (revokedDKIMPublicKeyHashes[publicKeyHash][user] == true) {
threshold += 2;
}
revokedDKIMPublicKeyHashes[publicKeyHash][register] = true;
return threshold;
}

emit DKIMPublicKeyHashRevoked(publicKeyHash, register);
function _stringEq(
string memory a,
string memory b
) internal pure returns (bool) {
return keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b));
}
}

0 comments on commit 08249d6

Please sign in to comment.