Line data Source code
1 : #include "fd_gui_config_parse.h"
2 :
3 : #include "../../ballet/json/fd_jtok.h"
4 :
5 : /* parse_field consumes the pending string value of j into out (out_sz
6 : bytes). A value that is not a string, or a string whose decoded
7 : form does not fit, leaves out empty and does not error j. */
8 :
9 : static void
10 : parse_field( fd_jtok_t * j,
11 : char * out,
12 9 : ulong out_sz ) {
13 9 : out[ 0 ] = '\0';
14 9 : if( FD_UNLIKELY( fd_jtok_peek( j )!=FD_JTOK_STR ) ) return;
15 :
16 6 : char const * raw = NULL; ulong raw_sz = 0UL;
17 6 : fd_jtok_raw( j, &raw, &raw_sz );
18 6 : if( FD_UNLIKELY( !raw ) ) return;
19 :
20 6 : fd_jtok_t s[1]; fd_jtok_init( s, raw, raw_sz );
21 6 : fd_jtok_cstr( s, out, out_sz );
22 6 : if( FD_UNLIKELY( fd_jtok_fini( s ) ) ) out[ 0 ] = '\0';
23 6 : }
24 :
25 : int
26 : fd_gui_config_parse_validator_info( uchar const * data,
27 : ulong sz,
28 12 : fd_gui_config_parse_info_t * info ) {
29 : /*
30 : pub struct ConfigKeys {
31 : #[cfg_attr(feature = "serde", serde(with = "short_vec"))]
32 : pub keys: Vec<(Pubkey, bool)>,
33 : }
34 :
35 : The memory layout of a ConfigProgram account is a bincode serialized
36 : ConfigKeys followed immediately by a stringified json object
37 : containing the desired info.
38 :
39 : The short_vec serialization format is a 1-3 bytes size field (where
40 : the highest bit in a given byte is a continuation bit) followed by
41 : serialized elements in the vector (in this case, each element is a
42 : 32byte pubkey followed by a 1byte bool. For our simple parser, we
43 : only need to consider vectors smaller than 128 elements.
44 :
45 : The JSON schema for a validator info object is the following
46 :
47 : {
48 : "name": "<validator name>",
49 : "website": "<website url>",
50 : "details": "<validator details>",
51 : "iconUrl": "<icon url>"
52 : }
53 : */
54 12 : ulong i = 0UL;
55 :
56 48 : #define CHECK( cond ) do { \
57 48 : if( FD_UNLIKELY( !(cond) ) ) { \
58 0 : return 0; \
59 0 : } \
60 48 : } while( 0 )
61 :
62 : /* CHECK that it is safe to read at least n more bytes assuming i is
63 : the current location. n is untrusted and could trigger overflow, so
64 : don't do i+n<=payload_sz */
65 48 : #define CHECK_LEFT( n ) CHECK( (n)<=(sz-i) )
66 :
67 12 : CHECK_LEFT( 1UL ); uchar ck_sz = FD_LOAD( uchar, data+i ); i++;
68 12 : if( FD_UNLIKELY( ck_sz!=2 ) ) return 0;
69 :
70 12 : struct __attribute__((packed, aligned(1))) config_keys {
71 12 : fd_pubkey_t pubkey;
72 12 : uchar is_signer;
73 12 : };
74 :
75 12 : struct config_keys * data_config_keys = (struct config_keys *)(data + i);
76 12 : CHECK_LEFT( (sizeof(fd_pubkey_t) + 1UL)*ck_sz ); i += (sizeof(fd_pubkey_t) + 1UL)*ck_sz;
77 12 : CHECK_LEFT( FD_GUI_CONFIG_PARSE_VALIDATOR_INFO_MAX_SZ );
78 :
79 : /* First entry should be Va1idator1nfo111111111111111111111111111111 */
80 12 : uchar expected[ 32UL ] = { 0x07, 0x51, 0x97, 0x01, 0x74, 0x48, 0xf2, 0xac, 0x5d, 0xc2, 0x3c, 0x9e, 0xbc, 0x7a, 0xc7, 0x8c, 0x0a, 0x27, 0x25, 0x7a, 0xc6, 0x14, 0x45, 0x8d, 0xe0, 0xa4, 0xf1, 0x6f, 0x80, 0x00, 0x00, 0x00 };
81 12 : if( FD_UNLIKELY( memcmp( data_config_keys[0].pubkey.uc, expected, sizeof(fd_pubkey_t) ) || data_config_keys[0].is_signer ) ) return 0;
82 :
83 : /* The config program only requires signatures from keys flagged
84 : is_signer, so an unsigned identity key could be anyone's */
85 12 : if( FD_UNLIKELY( data_config_keys[1].is_signer!=1 ) ) return 0;
86 :
87 6 : CHECK_LEFT( sizeof(ulong) ); ulong json_str_sz = FD_LOAD( ulong, data+i ); i += sizeof(ulong);
88 :
89 6 : CHECK_LEFT( json_str_sz );
90 :
91 6 : #undef CHECK
92 6 : #undef CHECK_LEFT
93 :
94 6 : info->name [ 0 ] = '\0';
95 6 : info->website [ 0 ] = '\0';
96 6 : info->details [ 0 ] = '\0';
97 6 : info->icon_uri [ 0 ] = '\0';
98 6 : info->keybase_username[ 0 ] = '\0';
99 :
100 6 : fd_jtok_t j[1]; fd_jtok_init( j, data+i, json_str_sz );
101 6 : fd_jtok_str_t key;
102 6 : fd_jtok_obj_enter( j );
103 15 : while( fd_jtok_obj_next( j, &key ) ) {
104 9 : if( fd_jtok_str_eq( &key, "name" ) ) parse_field( j, info->name, sizeof(info->name) );
105 3 : else if( fd_jtok_str_eq( &key, "website" ) ) parse_field( j, info->website, sizeof(info->website) );
106 0 : else if( fd_jtok_str_eq( &key, "details" ) ) parse_field( j, info->details, sizeof(info->details) );
107 0 : else if( fd_jtok_str_eq( &key, "iconUrl" ) ) parse_field( j, info->icon_uri, sizeof(info->icon_uri) );
108 0 : else if( fd_jtok_str_eq( &key, "keybaseUsername" ) ) parse_field( j, info->keybase_username, sizeof(info->keybase_username) );
109 9 : }
110 6 : if( FD_UNLIKELY( fd_jtok_fini( j ) ) ) return 0;
111 :
112 3 : fd_memcpy( info->pubkey.uc, data_config_keys[1].pubkey.uc, sizeof(fd_pubkey_t) );
113 3 : return 1;
114 6 : }
|