Today I Learned: The rules for a valid Steem account username (and how to find out stuff by reading sourcecode)

in #til7 years ago (edited)

Have


you ever wondered what the rules are for a Steem username?

In summary, the first character must be a-z (lower case), the last character can be a-z or 0-9 (lower case letter or number) and second and up to second last can be a-z, 0-9 and '-' (hyphen). The maximum length is 16, and the minimum is 3 characters.

I am writing an app for python3/django/piston for selling accounts, and the first thing I need to know is how to check for a valid username, thus I looked into this.

I wasn't finding a satisfactory answer anywhere I searched, so first I dug into the piston-steem code to look for the 'create account' function, and that didn't seem to have the actual validity test, and I discovered that with github you can search an entire project filesystem and it will show you matches.

Here is the code from the steem blockchain source code that checks them:

bool is_valid_account_name( const string& name )
{
#if STEEMIT_MIN_ACCOUNT_NAME_LENGTH < 3
#error This is_valid_account_name implementation implicitly enforces minimum name length of 3.
#endif

   const size_t len = name.size();
   if( len < STEEMIT_MIN_ACCOUNT_NAME_LENGTH )
      return false;

   if( len > STEEMIT_MAX_ACCOUNT_NAME_LENGTH )
      return false;

   size_t begin = 0;
   while( true )
   {
      size_t end = name.find_first_of( '.', begin );
      if( end == std::string::npos )
         end = len;
      if( end - begin < 3 )
         return false;
      switch( name[begin] )
      {
         case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h':
         case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p':
         case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x':
         case 'y': case 'z':
            break;
         default:
            return false;
      }
      switch( name[end-1] )
      {
         case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h':
         case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p':
         case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x':
         case 'y': case 'z':
         case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
         case '8': case '9':
            break;
         default:
            return false;
      }
      for( size_t i=begin+1; i<end-1; i++ )
      {
         switch( name[i] )
         {
            case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h':
            case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p':
            case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x':
            case 'y': case 'z':
            case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
            case '8': case '9':
            case '-':
               break;
            default:
               return false;
         }
      }
      if( end == len )
         break;
      begin = end+1;
   }
   return true;
}

I find it odd that it does not use regular expression syntax, but this rather messy and repetitive multi-case statements for the tests. If it was regex, it would look like this:

[a-z][a-z0-9\-]+[a-z0-9]

Maybe this is more optimised since I think this check gets done every time a username appears in an API call. At minimum I would usually write something like

if character >= 'a' and character <= 'z'

This code above theoretically would push out something looking more like this:

if character = 'a'
    return true
elseif character = 'b' 
....

You get the idea.

Well, no matter, now you also know what a valid Steem account username can be.

update:

I also was looking for how to generate role (public, "STMasoethuastoehu" type) keys and it took me some searching but I eventually found the responsible code:

pair<public_key_type,string> wallet_api::get_private_key_from_password( string account, string role, string password )const {
   auto seed = account + role + password;
   FC_ASSERT( seed.size() );
   auto secret = fc::sha256::hash( seed.c_str(), seed.size() );
   auto priv = fc::ecc::private_key::regenerate( secret );
   return std::make_pair( public_key_type( priv.get_public_key() ), key_to_wif( priv ) );
}

It is going to take a little time to follow all the breadcrumbs like the role key strings and the correct functions referred to in there, but from that I should be able to write a javascript that generates them for the username purchase transaction. That last line starting return std::make_pair is a function that takes the private role subkey and generates the public key.

The previous lines generate that role private key out of it, but you can't generate the secret key (password) backwards from the role keys. This algorithm will be going into a simple html page I direct users to download that takes a secret and generates just the public keys, which are needed for the create_account function.

😎


We can't code here! This is Whale country!

Written with StackEdit.

Sort:  

Hello my friend the Post this wonderful https://steemit.com/@tohamy7

Thank you I just found this today and needed it!

Loading...

We can't code here! This is Whale country!

lol ... it certainly is NOW :) so the only option is to keep the talent underground and let them eat cake, right :)

i had it at 21 characters for some reason in VARCHAR ... that's a post-thanks for the post then

r.i.p. SteemIt (well the only interesting bit thats left is to hack around on it ... unless you're one of said whales :p)

you saw that coming before i got here

4b8.gif

Coin Marketplace

STEEM 0.18
TRX 0.13
JST 0.029
BTC 58625.96
ETH 3101.66
USDT 1.00
SBD 2.41