Skip to content

Commit

Permalink
Add authentication and exit registration to exit db contract
Browse files Browse the repository at this point in the history
This patch overhauls the exit db contract in a number of ways to prepare
it for a production deployment.

1) The identity struct now stores mesh ip's as a uint128 and wireguard
   keys as a uint256 these are both superior storage methods to strings
   becuase valid ipv6 addresses and wireguard addresses are exactly
   these sizes. It's not otherwise possible to perform sufficient
   vlaidation of incoming data to ensure that any given string is a
   valid wireguard key or ipv6 address

2) Functions for adding and removing admins and permissions for user
   management in general. This is a required feature for a production
   implementation of this contract. Currently the 'super admin' capable
   of adding and removing individual admins is intended to be a Genosis
   Safe but could in theory simply be a secure single address

3) The capability to remove users has been added

4) The exit registry has been added as a parallel but otherwise
   identical data store to the user data store.

Currently this contract does not have any valid unit tests (also a
requirement for production) and needs to be hooked into the router
software.
  • Loading branch information
jkilpatr committed Sep 28, 2023
1 parent f799b81 commit d55092a
Show file tree
Hide file tree
Showing 6 changed files with 377 additions and 48 deletions.
371 changes: 343 additions & 28 deletions solidity/contracts/AltheaDB.sol
Original file line number Diff line number Diff line change
@@ -1,54 +1,369 @@
//SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.21; // Force solidity compliance

/// Identity struct
struct Identity {
uint128 mesh_ip;
uint256 wg_key;
address eth_addr;
}

/// Thrown when the caller is not authorized to register users
error UnathorizedCaller();
error DuplicateUser();
error DuplicateAdmin();
error IdentityNotFound();
error AdminNotFound();

contract AltheaDB {
constructor() {}
/// The admin address that is allowed to update who is on the
/// user admin and exit admin lists. This could be an individual
/// account or a multisig
address public immutable state_admin;
/// A list of addresses allowed to add and remove users from the list of users
address[] public state_UserAdmins;
/// A list of addresses allowed to add and remove exits from the list of exits
address[] public state_ExitAdmins;

// Mappings to regsitered clients
Identity[] public state_registeredUsers;
// Mappings to regsitered exits
Identity[] public state_registeredExits;

event UserRegisteredEvent(Identity indexed _user);
event UserRemovedEvent(Identity indexed _user);
event ExitRegisteredEvent(Identity indexed _user);
event ExitRemovedEvent(Identity indexed _user);
event UserAdminAddedEvent(address indexed _admin);
event UserAdminRemovedEvent(address indexed _admin);
event ExitAdminAddedEvent(address indexed _admin);
event ExitAdminRemovedEvent(address indexed _admin);

// Identity struct
struct Identity {
string mesh_ip;
string wg_key;
address eth_addr;
constructor(address _admin) {
state_admin = _admin;
}

// Mappings to regsitered clients
Identity[] private registered_users;
mapping(string => Identity) private wg_key_to_reg_users_map;
mapping(string => Identity) private mesh_ip_to_reg_users_map;
mapping(address => Identity) private eth_addr_to_reg_users_map;
// start utility function

function get_null_identity() public pure returns (Identity memory) {
return Identity({mesh_ip: 0, wg_key: 0, eth_addr: address(0)});
}

function is_null_identity(
Identity calldata input
) public pure returns (bool) {
return identities_are_equal(input, get_null_identity());
}

function identities_are_equal(
Identity memory a,
Identity memory b
) public pure returns (bool) {
if (a.mesh_ip != b.mesh_ip) {
return false;
}
if (a.wg_key != b.wg_key) {
return false;
}
if (a.eth_addr != b.eth_addr) {
return false;
}
return true;
}

function is_user_admin(address potential_admin) public view returns (bool) {
for (uint256 i = 0; i < state_UserAdmins.length; i++) {
if (potential_admin == state_UserAdmins[i]) {
return true;
}
}
return false;
}

function is_exit_admin(address potential_admin) public view returns (bool) {
for (uint256 i = 0; i < state_UserAdmins.length; i++) {
if (potential_admin == state_ExitAdmins[i]) {
return true;
}
}
return false;
}

/// Deletes an entry of the provided array
function delete_array_entry(uint index, Identity[] storage array) private {
require(index < array.length);
// copy the last element into the index that we want to delete
// in the case that we want to delete the last element, just skip this
if (index != array.length -1) {
array[index] = array[array.length - 1];
}
// drop the new duplicated end element effectively deleting the originally
// specified index
array.pop();
}

/// Deletes an entry of the provided array
function delete_array_entry(uint index, address[] storage array) private {
require(index < array.length);
// copy the last element into the index that we want to delete
// in the case that we want to delete the last element, just skip this
if (index != array.length -1) {
array[index] = array[array.length - 1];
}
// drop the new duplicated end element effectively deleting the originally
// specified index
array.pop();
}

function get_index_of_id(Identity memory id, Identity[] memory array) private pure returns (uint256) {
for (uint256 i = 0; i < array.length; i++) {
if (identities_are_equal(array[i], id)) {
return i;
}
}
revert IdentityNotFound();
}

function get_index_of_admin(address admin, address[] memory array) private pure returns (uint256) {
for (uint256 i = 0; i < array.length; i++) {
if (admin == array[i]) {
return i;
}
}
revert AdminNotFound();
}

/// Checks both the exit and the client lists for any entry with any
/// sort of duplicate ID component
function check_for_any_duplicates(
Identity calldata entry
) public view returns (bool) {
if (
!identities_are_equal(
get_registered_exit_with_eth_addr(entry.eth_addr),
get_null_identity()
)
) {
return true;
}
if (
!identities_are_equal(
get_registered_exit_with_mesh_ip(entry.mesh_ip),
get_null_identity()
)
) {
return true;
}
if (
!identities_are_equal(
get_registered_exit_with_wg_key(entry.wg_key),
get_null_identity()
)
) {
return true;
}

if (
!identities_are_equal(
get_registered_client_with_eth_addr(entry.eth_addr),
get_null_identity()
)
) {
return true;
}
if (
!identities_are_equal(
get_registered_client_with_mesh_ip(entry.mesh_ip),
get_null_identity()
)
) {
return true;
}
if (
!identities_are_equal(
get_registered_client_with_wg_key(entry.wg_key),
get_null_identity()
)
) {
return true;
}
return false;
}

// start user and exit management functions

// Add a new registered user
function add_registered_user(Identity memory entry) public {
registered_users.push(entry);
wg_key_to_reg_users_map[entry.wg_key] = entry;
mesh_ip_to_reg_users_map[entry.mesh_ip] = entry;
eth_addr_to_reg_users_map[entry.eth_addr] = entry;
function add_registered_user(Identity calldata entry) public {
if (is_user_admin(msg.sender)) {
// if any client or exit currently registered has overlapping data, do not allow the
// registration to continue
if (check_for_any_duplicates(entry)) {
revert DuplicateUser();
}

state_registeredUsers.push(entry);
emit UserRegisteredEvent(entry);
} else {
revert UnathorizedCaller();
}
}

// Remove a new registered user
function remove_registered_user(Identity calldata entry) public {
if (is_user_admin(msg.sender)) {
uint256 index = get_index_of_id(entry, state_registeredUsers);
delete_array_entry(index, state_registeredUsers);
emit UserRemovedEvent(entry);
} else {
revert UnathorizedCaller();
}
}

// Add a new registered exit
function add_registered_exit(Identity calldata entry) public {
if (is_exit_admin(msg.sender)) {
// if any client or exit currently registered has overlapping data, do not allow the
// registration to continue
if (check_for_any_duplicates(entry)) {
revert DuplicateUser();
}

state_registeredExits.push(entry);
emit ExitRegisteredEvent(entry);
} else {
revert UnathorizedCaller();
}
}

// Get all registered users
function get_all_registered_users()
public
view
returns (Identity[] memory)
{
return registered_users;
// Remove a new registered exit
function remove_registered_exit(Identity calldata entry) public {
if (is_exit_admin(msg.sender)) {
uint256 index = get_index_of_id(entry, state_registeredExits);
delete_array_entry(index, state_registeredExits);
emit ExitRemovedEvent(entry);
} else {
revert UnathorizedCaller();
}
}

// start user query functions


function get_registered_client_with_wg_key(
string memory wg_key
uint256 wg_key
) public view returns (Identity memory) {
return wg_key_to_reg_users_map[wg_key];
for (uint256 i = 0; i < state_registeredUsers.length; i++) {
if (state_registeredUsers[i].wg_key == wg_key) {
return state_registeredUsers[i];
}
}
return get_null_identity();
}

function get_registered_client_with_mesh_ip(
string memory mesh_ip
uint128 mesh_ip
) public view returns (Identity memory) {
return mesh_ip_to_reg_users_map[mesh_ip];
for (uint256 i = 0; i < state_registeredUsers.length; i++) {
if (state_registeredUsers[i].mesh_ip == mesh_ip) {
return state_registeredUsers[i];
}
}
return get_null_identity();
}

function get_registered_client_with_eth_addr(
address eth_addr
) public view returns (Identity memory) {
return eth_addr_to_reg_users_map[eth_addr];
for (uint256 i = 0; i < state_registeredUsers.length; i++) {
if (state_registeredUsers[i].eth_addr == eth_addr) {
return state_registeredUsers[i];
}
}
return get_null_identity();
}

function get_registered_exit_with_wg_key(
uint256 wg_key
) public view returns (Identity memory) {
for (uint256 i = 0; i < state_registeredExits.length; i++) {
if (state_registeredExits[i].wg_key == wg_key) {
return state_registeredExits[i];
}
}
return get_null_identity();
}

function get_registered_exit_with_mesh_ip(
uint128 mesh_ip
) public view returns (Identity memory) {
for (uint256 i = 0; i < state_registeredExits.length; i++) {
if (state_registeredExits[i].mesh_ip == mesh_ip) {
return state_registeredExits[i];
}
}
return get_null_identity();
}

function get_registered_exit_with_eth_addr(
address eth_addr
) public view returns (Identity memory) {
for (uint256 i = 0; i < state_registeredExits.length; i++) {
if (state_registeredExits[i].eth_addr == eth_addr) {
return state_registeredExits[i];
}
}
return get_null_identity();
}

// start admin management functions

// Add a new user admin
function add_user_admin(address entry) public {
if (state_admin == msg.sender) {
if (is_user_admin(entry)) {
revert DuplicateAdmin();
}

state_UserAdmins.push(entry);
emit UserAdminAddedEvent(entry);
} else {
revert UnathorizedCaller();
}
}

// Remove a user admin
function remove_user_admin(address entry) public {
if (state_admin == msg.sender) {
uint256 index = get_index_of_admin(entry, state_UserAdmins);
delete_array_entry(index, state_UserAdmins);
emit UserAdminAddedEvent(entry);
} else {
revert UnathorizedCaller();
}
}

// Add a new exit admin
function add_exit_admin(address entry) public {
if (state_admin == msg.sender) {
if (is_exit_admin(entry)) {
revert DuplicateAdmin();
}

state_ExitAdmins.push(entry);
emit ExitAdminAddedEvent(entry);
} else {
revert UnathorizedCaller();
}
}

// Remove a exit admin
function remove_exit_admin(address entry) public {
if (state_admin == msg.sender) {
uint256 index = get_index_of_admin(entry, state_ExitAdmins);
delete_array_entry(index, state_ExitAdmins);
emit UserAdminAddedEvent(entry);
} else {
revert UnathorizedCaller();
}
}
}
Loading

0 comments on commit d55092a

Please sign in to comment.