Clean up is_valid_name and remove child accounts; #15, #93

This commit is contained in:
Vikram Rajkumar 2015-06-29 15:07:57 -04:00
parent 3ac8ccaa39
commit f0ea015ccf
6 changed files with 113 additions and 117 deletions

View file

@ -70,18 +70,6 @@ void_result account_create_evaluator::do_evaluate( const account_create_operatio
FC_ASSERT( current_account_itr == acnt_indx.indices().get<by_name>().end() );
}
// verify child account authority
auto pos = op.name.find( '/' );
if( pos != string::npos )
{
// TODO: lookup account by op.owner.auths[0] and verify the name
// this should be a constant time lookup rather than log(N)
auto parent_account_itr = acnt_indx.indices().get<by_name>().find( op.name.substr(0,pos) );
FC_ASSERT( parent_account_itr != acnt_indx.indices().get<by_name>().end() );
FC_ASSERT( verify_authority( *parent_account_itr, authority::owner ) );
FC_ASSERT( op.owner.auths.find( parent_account_itr->id ) != op.owner.auths.end() );
}
return void_result();
} FC_CAPTURE_AND_RETHROW( (op) ) }

View file

@ -20,8 +20,11 @@
#define GRAPHENE_SYMBOL "CORE"
#define GRAPHENE_ADDRESS_PREFIX "GPH"
#define GRAPHENE_MIN_SYMBOL_NAME_LENGTH 3
#define GRAPHENE_MAX_SYMBOL_NAME_LENGTH 17
#define GRAPHENE_MIN_ACCOUNT_NAME_LENGTH 1
#define GRAPHENE_MAX_ACCOUNT_NAME_LENGTH 63
#define GRAPHENE_MIN_ASSET_SYMBOL_LENGTH 3
#define GRAPHENE_MAX_ASSET_SYMBOL_LENGTH 16
#define GRAPHENE_MAX_ASSET_NAME_LENGTH 127

View file

@ -210,15 +210,15 @@ namespace graphene { namespace chain {
account_transaction_history_object> account_transaction_history_id_type;
typedef object_id< implementation_ids, impl_witness_schedule_object_type, witness_schedule_object > witness_schedule_id_type;
typedef fc::array<char,GRAPHENE_MAX_SYMBOL_NAME_LENGTH> symbol_type;
typedef fc::ripemd160 block_id_type;
typedef fc::ripemd160 checksum_type;
typedef fc::ripemd160 transaction_id_type;
typedef fc::sha256 digest_type;
typedef fc::ecc::compact_signature signature_type;
typedef safe<int64_t> share_type;
typedef fc::sha224 secret_hash_type;
typedef uint16_t weight_type;
typedef fc::array<char, GRAPHENE_MAX_ASSET_SYMBOL_LENGTH> symbol_type;
typedef fc::ripemd160 block_id_type;
typedef fc::ripemd160 checksum_type;
typedef fc::ripemd160 transaction_id_type;
typedef fc::sha256 digest_type;
typedef fc::ecc::compact_signature signature_type;
typedef safe<int64_t> share_type;
typedef fc::sha224 secret_hash_type;
typedef uint16_t weight_type;
/**
* @brief An ID for some votable object

View file

@ -23,77 +23,99 @@
namespace graphene { namespace chain {
/**
* Valid symbols have at most a single "." that is not the first or last character.
* Valid symbols can contain [A, Z], and '.'
* They must start with [A, Z]
* They must end with [A, Z]
* They can contain a maximum of one '.'
*/
bool is_valid_symbol( const string& symbol )
{
if( symbol.size() < GRAPHENE_MIN_SYMBOL_NAME_LENGTH || symbol.size() > GRAPHENE_MAX_SYMBOL_NAME_LENGTH )
if( symbol.size() < GRAPHENE_MIN_ASSET_SYMBOL_LENGTH )
return false;
if( symbol.front() == '.' || symbol.back() == '.' )
if( symbol.size() > GRAPHENE_MAX_ASSET_SYMBOL_LENGTH )
return false;
if( !isalpha( symbol.front() ) )
return false;
if( !isalpha( symbol.back() ) )
return false;
bool dot_already_present = false;
for( const auto c : symbol )
{
if( isalpha( c ) && isupper( c ) )
continue;
if( c == '.' )
{
if( dot_already_present )
return false;
dot_already_present = true;
continue;
}
else if( !isalpha( c ) || !isupper( c ) )
{
return false;
}
return false;
}
return true;
}
/**
* Valid names are all lower case, start with [a-z] and may
* have "." or "-" in the name along with a single '/'. The
* next character after a "/", "." or "-" cannot be [0-9] or
* another '.', '-'.
*
* Valid names can contain [a, z], [0, 9], '.', and '-'
* They must start with [a, z]
* They must end with [a, z] or [0, 9]
* '.' must be followed by [a, z]
* '-' must be followed by [a, z] or [0, 9]
*/
bool is_valid_name( const string& s )
bool is_valid_name( const string& name )
{
if( s.size() < 2 ) return false;
if( s.size() >= 64 ) return false;
if( name.size() < GRAPHENE_MIN_ACCOUNT_NAME_LENGTH )
return false;
int num_slash = 0;
char prev = ' ';
for( auto c : s )
{
if( c >= 'a' && c <= 'z' ){}
else if( c >= '0' && c <= '9' )
{
if( prev == ' ' || prev == '.' || prev == '/' ) return false;
}
else switch( c )
{
case '/':
if( ++num_slash > 1 ) return false;
case '.':
if( prev == '-' ) return false;
case '-':
if( prev == ' ' || prev == '/' || prev == '.' ) return false;
break;
default:
return false;
}
prev = c;
}
switch( s.back() )
{
case '/': case '-': case '.':
return false;
default:
return true;
}
if( name.size() > GRAPHENE_MAX_ACCOUNT_NAME_LENGTH )
return false;
if( !isalpha( name.front() ) )
return false;
if( !isalpha( name.back() ) && !isdigit( name.back() ) )
return false;
for( size_t i = 0; i < name.size(); ++i )
{
const auto c = name.at( i );
if( isalpha( c ) && islower( c ) )
continue;
if( isdigit( c ) )
continue;
if( c == '.' )
{
const auto next = name.at( i + 1 );
if( !isalpha( next ) )
return false;
continue;
}
if( c == '-' )
{
const auto next = name.at( i + 1 );
if( !isalpha( next ) && !isdigit( next ) )
return false;
continue;
}
return false;
}
return true;
}
bool is_cheap_name( const string& n )

View file

@ -41,12 +41,38 @@ using namespace graphene::db;
BOOST_FIXTURE_TEST_SUITE( basic_tests, database_fixture )
/** verify that names are RFC-1035 compliant https://tools.ietf.org/html/rfc1035
/**
* Verify that names are RFC-1035 compliant https://tools.ietf.org/html/rfc1035
* https://github.com/cryptonomex/graphene/issues/15
*/
BOOST_AUTO_TEST_CASE( valid_name_test )
{
BOOST_REQUIRE( is_valid_name( "a" ) );
BOOST_REQUIRE( !is_valid_name( "A" ) );
BOOST_REQUIRE( !is_valid_name( "0" ) );
BOOST_REQUIRE( !is_valid_name( "." ) );
BOOST_REQUIRE( !is_valid_name( "-" ) );
BOOST_REQUIRE( is_valid_name( "aa" ) );
BOOST_REQUIRE( !is_valid_name( "aA" ) );
BOOST_REQUIRE( is_valid_name( "a0" ) );
BOOST_REQUIRE( !is_valid_name( "a." ) );
BOOST_REQUIRE( !is_valid_name( "a-" ) );
BOOST_REQUIRE( is_valid_name( "aaa" ) );
BOOST_REQUIRE( !is_valid_name( "aAa" ) );
BOOST_REQUIRE( is_valid_name( "a0a" ) );
BOOST_REQUIRE( is_valid_name( "a.a" ) );
BOOST_REQUIRE( is_valid_name( "a-a" ) );
BOOST_REQUIRE( is_valid_name( "aa0" ) );
BOOST_REQUIRE( !is_valid_name( "aA0" ) );
BOOST_REQUIRE( is_valid_name( "a00" ) );
BOOST_REQUIRE( !is_valid_name( "a.0" ) );
BOOST_REQUIRE( is_valid_name( "a-0" ) );
BOOST_REQUIRE( is_valid_name( "aaa-bbb-1" ) );
BOOST_REQUIRE( !is_valid_name( "aaa-bbb.1" ) );
BOOST_REQUIRE( !is_valid_name( "aaa,bbb-1" ) );
BOOST_REQUIRE( !is_valid_name( "aaa_bbb-1" ) );
@ -65,11 +91,12 @@ BOOST_AUTO_TEST_CASE( valid_name_test )
BOOST_REQUIRE( is_valid_name( "aaa.bbb-1" ) );
BOOST_REQUIRE( !is_valid_name( "aaa.bbb.1" ) );
BOOST_REQUIRE( is_valid_name( "aaa--bbb--1" ) );
BOOST_REQUIRE( is_valid_name( "xn--sandmnnchen-p8a.de" ) );
BOOST_REQUIRE( !is_valid_name( "aaa--bbb--1" ) );
BOOST_REQUIRE( !is_valid_name( "xn--sandmnnchen-p8a.de" ) );
BOOST_REQUIRE( is_valid_name( "xn-sandmnnchen-p8a.de" ) );
BOOST_REQUIRE( is_valid_name( "this-label-has-less-than-64-characters--63-to-be-really-precise" ) );
BOOST_REQUIRE( !is_valid_name( "this-label-has-more-than-63-characters---64-to-be-really-precise" ) );
BOOST_REQUIRE( is_valid_name( "this-label-has-less-than-64-char.acters-63-to-be-really-precise" ) );
BOOST_REQUIRE( !is_valid_name( "this-label-has-more-than-63-char.act.ers-64-to-be-really-precise" ) );
BOOST_REQUIRE( !is_valid_name( "none.of.these.labels.has.more.than-63.chars--but.still.not.valid" ) );
}

View file

@ -363,50 +363,6 @@ BOOST_AUTO_TEST_CASE( create_account_test )
}
}
BOOST_AUTO_TEST_CASE( child_account )
{
try {
INVOKE(create_account_test);
fc::ecc::private_key child_private_key = fc::ecc::private_key::generate();
fc::ecc::private_key nathan_private_key = fc::ecc::private_key::generate();
const auto& child_key = register_key(child_private_key.get_public_key());
const auto& nathan_key = register_key(nathan_private_key.get_public_key());
const account_object& nathan = get_account("nathan");
const account_object& root = create_account("root");
upgrade_to_lifetime_member(root);
skip_key_index_test = true;
db.modify(nathan, [nathan_key](account_object& a) {
a.owner = authority(1, nathan_key.get_id(), 1);
a.active = authority(1, nathan_key.get_id(), 1);
});
BOOST_CHECK(nathan.active.get_keys() == vector<key_id_type>{nathan_key.get_id()});
auto op = make_account("nathan/child");
op.registrar = root.id;
op.owner = authority(1, child_key.get_id(), 1);
op.active = authority(1, child_key.get_id(), 1);
trx.operations.emplace_back(op);
trx.sign(key_id_type(), delegate_priv_key);
BOOST_REQUIRE_THROW(PUSH_TX( db, trx ), fc::exception);
sign(trx, nathan_key.id,nathan_private_key);
BOOST_REQUIRE_THROW(PUSH_TX( db, trx ), fc::exception);
trx.signatures.clear();
op.owner = authority(1, account_id_type(nathan.id), 1);
trx.operations = {op};
trx.sign(key_id_type(), delegate_priv_key);
trx.sign(nathan_key.id, nathan_private_key);
db.push_transaction(trx);
BOOST_CHECK( get_account("nathan/child").active.auths == op.active.auths );
} catch (fc::exception& e) {
edump((e.to_detail_string()));
throw;
}
}
BOOST_AUTO_TEST_CASE( update_account )
{
try {