提交 4f94246b 编写于 作者: M Matias Romeo

Add permission api

上级 595e66d6
...@@ -141,6 +141,29 @@ class datastream<size_t> { ...@@ -141,6 +141,29 @@ class datastream<size_t> {
size_t _size; size_t _size;
}; };
/**
* Serialize a public_key into a stream
* @brief Serialize a public_key
* @param ds stream to write
* @param pubkey value to serialize
*/
template<typename Stream>
inline datastream<Stream>& operator<<(datastream<Stream>& ds, const public_key pubkey) {
ds.write( (const char*)&pubkey, sizeof(pubkey));
return ds;
}
/**
* Deserialize a public_key from a stream
* @brief Deserialize a public_key
* @param ds stream to read
* @param pubkey destination for deserialized value
*/
template<typename Stream>
inline datastream<Stream>& operator>>(datastream<Stream>& ds, public_key& pubkey) {
ds.read((char*)&pubkey, sizeof(pubkey));
return ds;
}
/** /**
* Serialize a key256 into a stream * Serialize a key256 into a stream
* @brief Serialize a key256 * @brief Serialize a key256
......
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#pragma once
#include <eosiolib/types.h>
extern "C" {
/**
* Checks if a set of public keys can authorize an account permission
* @brief Checks if a set of public keys can authorize an account permission
* @param account - the account owner of the permission
* @param permission - the permission name to check for authorization
* @param pubkeys - a pointer to an array of public keys (public_key)
* @param pubkeys_len - the lenght of the array of public keys
* @return 1 if the account permission can be authorized, 0 otherwise
*/
int32_t check_authorization( account_name account, permission_name permission, char* pubkeys, uint32_t pubkeys_len );
}
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "test_chain.cpp" #include "test_chain.cpp"
#include "test_transaction.cpp" #include "test_transaction.cpp"
#include "test_checktime.cpp" #include "test_checktime.cpp"
#include "test_permission.cpp"
extern "C" { extern "C" {
...@@ -148,6 +149,7 @@ extern "C" { ...@@ -148,6 +149,7 @@ extern "C" {
// test checktime // test checktime
WASM_TEST_HANDLER(test_checktime, checktime_pass); WASM_TEST_HANDLER(test_checktime, checktime_pass);
WASM_TEST_HANDLER(test_checktime, checktime_failure); WASM_TEST_HANDLER(test_checktime, checktime_failure);
/* /*
// test softfloat // test softfloat
WASM_TEST_HANDLER(test_softfloat, test_f32_add); WASM_TEST_HANDLER(test_softfloat, test_f32_add);
...@@ -157,6 +159,9 @@ extern "C" { ...@@ -157,6 +159,9 @@ extern "C" {
WASM_TEST_HANDLER(test_softfloat, test_f32_min); WASM_TEST_HANDLER(test_softfloat, test_f32_min);
*/ */
// test permission
WASM_TEST_HANDLER(test_permission, check_authorization);
//unhandled test call //unhandled test call
eosio_assert(false, "Unknown Test"); eosio_assert(false, "Unknown Test");
......
...@@ -277,3 +277,7 @@ struct test_softfloat { ...@@ -277,3 +277,7 @@ struct test_softfloat {
static void test_f32_min(); static void test_f32_min();
}; };
*/ */
struct test_permission {
static void check_authorization();
};
/**
* @file action_test.cpp
* @copyright defined in eos/LICENSE.txt
*/
#include <eosiolib/permission.h>
#include <eosiolib/db.h>
#include <eosiolib/eosio.hpp>
#include <eosiolib/print.hpp>
#include <eosiolib/compiler_builtins.h>
#include <eosiolib/serialize.hpp>
#include <eosiolib/action.hpp>
#include "test_api.hpp"
using namespace eosio;
struct check_auth {
account_name account;
permission_name permission;
vector<public_key> pubkeys;
EOSLIB_SERIALIZE( check_auth, (account)(permission)(pubkeys) )
};
void test_permission::check_authorization() {
auto params = unpack_action_data<check_auth>();
uint64_t res64 = (uint64_t)::check_authorization( params.account, params.permission,
(char*)params.pubkeys.data(), params.pubkeys.size()*sizeof(public_key) );
store_i64(current_receiver(), current_receiver(), current_receiver(), &res64, sizeof(uint64_t));
}
...@@ -842,6 +842,7 @@ flat_set<public_key_type> chain_controller::get_required_keys(const transaction& ...@@ -842,6 +842,7 @@ flat_set<public_key_type> chain_controller::get_required_keys(const transaction&
return checker.used_keys(); return checker.used_keys();
} }
class permission_visitor { class permission_visitor {
public: public:
permission_visitor(const chain_controller& controller) : _chain_controller(controller) {} permission_visitor(const chain_controller& controller) : _chain_controller(controller) {}
...@@ -863,6 +864,7 @@ time_point chain_controller::check_authorization( const vector<action>& actions, ...@@ -863,6 +864,7 @@ time_point chain_controller::check_authorization( const vector<action>& actions,
const flat_set<public_key_type>& provided_keys, const flat_set<public_key_type>& provided_keys,
bool allow_unused_signatures, bool allow_unused_signatures,
flat_set<account_name> provided_accounts )const flat_set<account_name> provided_accounts )const
{ {
auto checker = make_auth_checker( [&](const permission_level& p){ return get_permission(p).auth; }, auto checker = make_auth_checker( [&](const permission_level& p){ return get_permission(p).auth; },
permission_visitor(*this), permission_visitor(*this),
...@@ -963,6 +965,25 @@ time_point chain_controller::check_authorization( const vector<action>& actions, ...@@ -963,6 +965,25 @@ time_point chain_controller::check_authorization( const vector<action>& actions,
return max_delay; return max_delay;
} }
bool chain_controller::check_authorization( account_name account, permission_name permission,
flat_set<public_key_type> provided_keys,
bool allow_unused_signatures)const
{
auto checker = make_auth_checker( [&](const permission_level& p){ return get_permission(p).auth; },
get_global_properties().configuration.max_authority_depth,
provided_keys);
auto satisfied = checker.satisfied({account, permission});
if (satisfied && !allow_unused_signatures) {
EOS_ASSERT(checker.all_keys_used(), tx_irrelevant_sig,
"irrelevant signatures from these keys: ${keys}",
("keys", checker.unused_keys()));
}
return satisfied;
}
time_point chain_controller::check_transaction_authorization(const transaction& trx, time_point chain_controller::check_transaction_authorization(const transaction& trx,
const vector<signature_type>& signatures, const vector<signature_type>& signatures,
const vector<bytes>& cfd, const vector<bytes>& cfd,
......
...@@ -294,6 +294,16 @@ namespace eosio { namespace chain { ...@@ -294,6 +294,16 @@ namespace eosio { namespace chain {
flat_set<account_name> provided_accounts = flat_set<account_name>() flat_set<account_name> provided_accounts = flat_set<account_name>()
)const; )const;
/**
* @param account - the account owner of the permission
* @param permission - the permission name to check for authorization
* @param provided_keys - a set of public keys
*
* @return true if the provided keys are sufficient to authorize the account permission
*/
bool check_authorization( account_name account, permission_name permission,
flat_set<public_key_type> provided_keys,
bool allow_unused_signatures)const;
private: private:
const apply_handler* find_apply_handler( account_name contract, scope_name scope, action_name act )const; const apply_handler* find_apply_handler( account_name contract, scope_name scope, action_name act )const;
......
...@@ -752,6 +752,28 @@ class crypto_api : public context_aware_api { ...@@ -752,6 +752,28 @@ class crypto_api : public context_aware_api {
} }
}; };
class permission_api : public context_aware_api {
public:
using context_aware_api::context_aware_api;
bool check_authorization( account_name account, permission_name permission, array_ptr<char> packed_pubkeys, size_t datalen) {
vector<public_key_type> pub_keys;
datastream<const char*> ds( packed_pubkeys, datalen );
while(ds.remaining()) {
public_key_type pub;
fc::raw::unpack(ds, pub);
pub_keys.emplace_back(pub);
}
return context.controller.check_authorization(
account, permission,
{pub_keys.begin(), pub_keys.end()},
false
);
}
};
class string_api : public context_aware_api { class string_api : public context_aware_api {
public: public:
using context_aware_api::context_aware_api; using context_aware_api::context_aware_api;
...@@ -1501,6 +1523,10 @@ REGISTER_INTRINSICS(crypto_api, ...@@ -1501,6 +1523,10 @@ REGISTER_INTRINSICS(crypto_api,
(ripemd160, void(int, int, int) ) (ripemd160, void(int, int, int) )
); );
REGISTER_INTRINSICS(permission_api,
(check_authorization, int(int64_t, int64_t, int, int))
);
REGISTER_INTRINSICS(string_api, REGISTER_INTRINSICS(string_api,
(assert_is_utf8, void(int, int, int) ) (assert_is_utf8, void(int, int, int) )
); );
......
...@@ -81,7 +81,13 @@ struct test_chain_action { ...@@ -81,7 +81,13 @@ struct test_chain_action {
FC_REFLECT_TEMPLATE((uint64_t T), test_chain_action<T>, BOOST_PP_SEQ_NIL); FC_REFLECT_TEMPLATE((uint64_t T), test_chain_action<T>, BOOST_PP_SEQ_NIL);
struct check_auth {
account_name account;
permission_name permission;
vector<public_key_type> pubkeys;
};
FC_REFLECT(check_auth, (account)(permission)(pubkeys) );
bool expect_assert_message(const fc::exception& ex, string expected) { bool expect_assert_message(const fc::exception& ex, string expected) {
BOOST_TEST_MESSAGE("LOG : " << "expected: " << expected << ", actual: " << ex.get_log().at(0).get_message()); BOOST_TEST_MESSAGE("LOG : " << "expected: " << expected << ", actual: " << ex.get_log().at(0).get_message());
...@@ -1207,6 +1213,104 @@ BOOST_FIXTURE_TEST_CASE(types_tests, tester) { try { ...@@ -1207,6 +1213,104 @@ BOOST_FIXTURE_TEST_CASE(types_tests, tester) { try {
CALL_TEST_FUNCTION( *this, "test_types", "name_class", {}); CALL_TEST_FUNCTION( *this, "test_types", "name_class", {});
} FC_LOG_AND_RETHROW() } } FC_LOG_AND_RETHROW() }
/*************************************************************************************
* permission_tests test case
*************************************************************************************/
BOOST_FIXTURE_TEST_CASE(permission_tests, tester) { try {
produce_blocks(1);
create_account( N(testapi) );
produce_blocks(1);
set_code( N(testapi), test_api_wast );
produce_blocks(1);
auto get_result_uint64 = [&]() -> uint64_t {
const auto& db = control->get_database();
const auto* t_id = db.find<table_id_object, by_code_scope_table>(boost::make_tuple(N(testapi), N(testapi), N(testapi)));
FC_ASSERT(t_id != 0, "Table id not found");
const auto& idx = db.get_index<key_value_index, by_scope_primary>();
auto itr = idx.lower_bound(boost::make_tuple(t_id->id));
FC_ASSERT( itr != idx.end() && itr->t_id == t_id->id, "lower_bound failed");
FC_ASSERT( 0 == itr->value.size(), "unexpected result size");
return itr->primary_key;
};
CALL_TEST_FUNCTION( *this, "test_permission", "check_authorization",
fc::raw::pack( check_auth {
.account = N(testapi),
.permission = N(active),
.pubkeys = {
get_public_key(N(testapi), "active")
}
})
);
BOOST_CHECK_EQUAL( uint64_t(1), get_result_uint64() );
CALL_TEST_FUNCTION( *this, "test_permission", "check_authorization",
fc::raw::pack( check_auth {
.account = N(testapi),
.permission = N(active),
.pubkeys = {
public_key_type(string("EOS7GfRtyDWWgxV88a5TRaYY59XmHptyfjsFmHHfioGNJtPjpSmGX"))
}
})
);
BOOST_CHECK_EQUAL( uint64_t(0), get_result_uint64() );
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_permission", "check_authorization",
fc::raw::pack( check_auth {
.account = N(testapi),
.permission = N(active),
.pubkeys = {
get_public_key(N(testapi), "active"),
public_key_type(string("EOS7GfRtyDWWgxV88a5TRaYY59XmHptyfjsFmHHfioGNJtPjpSmGX"))
}
})), tx_irrelevant_sig,
[](const tx_irrelevant_sig& e) {
return expect_assert_message(e, "irrelevant signatures from these keys: [\"EOS7GfRtyDWWgxV88a5TRaYY59XmHptyfjsFmHHfioGNJtPjpSmGX\"]");
}
);
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_permission", "check_authorization",
fc::raw::pack( check_auth {
.account = N(noname),
.permission = N(active),
.pubkeys = {
get_public_key(N(testapi), "active")
}
})), fc::exception,
[](const fc::exception& e) {
return expect_assert_message(e, "unknown key");
}
);
CALL_TEST_FUNCTION( *this, "test_permission", "check_authorization",
fc::raw::pack( check_auth {
.account = N(testapi),
.permission = N(active),
.pubkeys = {}
})
);
BOOST_CHECK_EQUAL( uint64_t(0), get_result_uint64() );
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_permission", "check_authorization",
fc::raw::pack( check_auth {
.account = N(testapi),
.permission = N(noname),
.pubkeys = {
get_public_key(N(testapi), "active")
}
})), fc::exception,
[](const fc::exception& e) {
return expect_assert_message(e, "unknown key");
}
);
} FC_LOG_AND_RETHROW() }
#if 0 #if 0
/************************************************************************************* /*************************************************************************************
* privileged_tests test case * privileged_tests test case
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册