Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions contracts/sysio.system/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ set(SYSIO_SYSTEM_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/finalizer_key.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/peer_keys.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/trx_priority.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/expandauth.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/block_info.cpp)

set(SYSIO_SYSTEM_HEADERS
Expand Down
15 changes: 15 additions & 0 deletions contracts/sysio.system/include/sysio.system/sysio.system.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,20 @@ namespace sysiosystem {
[[sysio::action]]
void limitauthchg( const name& account, const std::vector<name>& allow_perms, const std::vector<name>& disallow_perms );

/**
* Expand the authority of a permission by adding keys and/or account permissions.
* Can only be called by the system contract itself (privileged).
*
* @param account - the account whose permission to expand
* @param permission - the permission name to expand
* @param keys - vector of key_weight entries to add
* @param accounts - vector of permission_level_weight entries to add
*/
[[sysio::action]]
void expandauth( const name& account, const name& permission,
const std::vector<key_weight>& keys,
const std::vector<permission_level_weight>& accounts );

/**
* On Link Auth notify to catch auth.ext stuff for sig-em
*/
Expand All @@ -514,6 +528,7 @@ namespace sysiosystem {
using setpriv_action = sysio::action_wrapper<"setpriv"_n, &system_contract::setpriv>;
using setalimits_action = sysio::action_wrapper<"setalimits"_n, &system_contract::setalimits>;
using setparams_action = sysio::action_wrapper<"setparams"_n, &system_contract::setparams>;
using expandauth_action = sysio::action_wrapper<"expandauth"_n, &system_contract::expandauth>;

private:
// Implementation details:
Expand Down
97 changes: 97 additions & 0 deletions contracts/sysio.system/src/expandauth.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#include <sysio.system/sysio.system.hpp>

#include <algorithm>
#include <cstring>

namespace sysio { namespace internal_use_do_not_use {
extern "C" {
__attribute__((sysio_wasm_import))
int32_t get_permission_lower_bound(uint64_t account, uint64_t permission, char* buffer, uint32_t buffer_size);
}
}}

namespace sysiosystem {

void system_contract::expandauth( const name& account, const name& permission,
const std::vector<key_weight>& new_keys,
const std::vector<permission_level_weight>& new_accounts ) {
require_auth( get_self() );

check( sysio::is_account(account), "account does not exist" );
check( !new_keys.empty() || !new_accounts.empty(),
"must provide at least one key or account to add" );

// Read current permission via raw intrinsic
char name_buf[8];
int32_t sz = sysio::internal_use_do_not_use::get_permission_lower_bound(
account.value, permission.value, name_buf, sizeof(name_buf) );
check( sz > 0, "permission does not exist" );

// Verify exact match (first 8 bytes of serialized data is the permission name)
sysio::name returned_name;
std::memcpy( &returned_name, name_buf, sizeof(returned_name) );
check( returned_name == permission, "permission does not exist" );

// Read full permission record
std::vector<char> buf( static_cast<size_t>(sz) );
sysio::internal_use_do_not_use::get_permission_lower_bound(
account.value, permission.value, buf.data(), buf.size() );

// Deserialize permission record fields:
// name perm_name, name parent, time_point last_updated, authority auth
sysio::datastream<const char*> ds( buf.data(), buf.size() );
sysio::name perm_name, parent;
sysio::time_point last_updated;
authority auth;
ds >> perm_name >> parent >> last_updated >> auth;

// Add new keys, skipping duplicates
for( const auto& kw : new_keys ) {
bool found = false;
for( const auto& existing : auth.keys ) {
if( existing.key == kw.key ) {
found = true;
break;
}
}
if( !found ) {
auth.keys.push_back( kw );
}
}

// Add new accounts, skipping duplicates
for( const auto& aw : new_accounts ) {
bool found = false;
for( const auto& existing : auth.accounts ) {
if( existing.permission == aw.permission ) {
found = true;
break;
}
}
if( !found ) {
auth.accounts.push_back( aw );
}
}

// Sort keys and accounts (required by authority validation)
std::sort( auth.keys.begin(), auth.keys.end(),
[]( const key_weight& a, const key_weight& b ) {
return a.key < b.key;
});
std::sort( auth.accounts.begin(), auth.accounts.end(),
[]( const permission_level_weight& a, const permission_level_weight& b ) {
return a.permission < b.permission;
});

// Send inline updateauth action
// Use the account's own permission as authorization; the system contract
// is privileged so it can provide this auth on inline actions.
sysio::action(
{ sysio::permission_level{ account, permission } },
get_self(),
"updateauth"_n,
std::make_tuple( account, permission, parent, auth )
).send();
}

} // namespace sysiosystem
Loading
Loading