@@ -904,7 +904,7 @@ pub struct NodeAnnouncementInfo {
904904 /// Moniker assigned to the node.
905905 /// May be invalid or malicious (eg control chars),
906906 /// should not be exposed to the user.
907- pub alias : [ u8 ; 32 ] ,
907+ pub alias : NodeAlias ,
908908 /// Internet-level addresses via which one can connect to the node
909909 pub addresses : Vec < NetAddress > ,
910910 /// An initial announcement of the node
@@ -923,6 +923,51 @@ impl_writeable_tlv_based!(NodeAnnouncementInfo, {
923923 ( 10 , addresses, vec_type) ,
924924} ) ;
925925
926+ /// A user-defined name for a node, which may be used when displaying the node in a graph.
927+ ///
928+ /// Since node aliases are provided by third parties, they are a potential avenue for injection
929+ /// attacks. Care must be taken when processing.
930+ #[ derive( Clone , Debug , PartialEq ) ]
931+ pub struct NodeAlias ( pub [ u8 ; 32 ] ) ;
932+
933+ impl fmt:: Display for NodeAlias {
934+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> Result < ( ) , fmt:: Error > {
935+ let control_symbol = core:: char:: REPLACEMENT_CHARACTER ;
936+ let first_null = self . 0 . iter ( ) . position ( |b| * b == 0 ) . unwrap_or ( self . 0 . len ( ) ) ;
937+ let bytes = self . 0 . split_at ( first_null) . 0 ;
938+ match core:: str:: from_utf8 ( bytes) {
939+ Ok ( alias) => {
940+ for c in alias. chars ( ) {
941+ let mut bytes = [ 0u8 ; 4 ] ;
942+ let c = if !c. is_control ( ) { c } else { control_symbol } ;
943+ f. write_str ( c. encode_utf8 ( & mut bytes) ) ?;
944+ }
945+ } ,
946+ Err ( _) => {
947+ for c in bytes. iter ( ) . map ( |b| * b as char ) {
948+ // Display printable ASCII characters
949+ let mut bytes = [ 0u8 ; 4 ] ;
950+ let c = if c >= '\x20' && c <= '\x7e' { c } else { control_symbol } ;
951+ f. write_str ( c. encode_utf8 ( & mut bytes) ) ?;
952+ }
953+ } ,
954+ } ;
955+ Ok ( ( ) )
956+ }
957+ }
958+
959+ impl Writeable for NodeAlias {
960+ fn write < W : Writer > ( & self , w : & mut W ) -> Result < ( ) , io:: Error > {
961+ self . 0 . write ( w)
962+ }
963+ }
964+
965+ impl Readable for NodeAlias {
966+ fn read < R : io:: Read > ( r : & mut R ) -> Result < Self , DecodeError > {
967+ Ok ( NodeAlias ( Readable :: read ( r) ?) )
968+ }
969+ }
970+
926971#[ derive( Clone , Debug , PartialEq ) ]
927972/// Details about a node in the network, known from the network announcement.
928973pub struct NodeInfo {
@@ -1126,7 +1171,7 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
11261171 features : msg. features . clone ( ) ,
11271172 last_update : msg. timestamp ,
11281173 rgb : msg. rgb ,
1129- alias : msg. alias ,
1174+ alias : NodeAlias ( msg. alias ) ,
11301175 addresses : msg. addresses . clone ( ) ,
11311176 announcement_message : if should_relay { full_msg. cloned ( ) } else { None } ,
11321177 } ) ;
@@ -1627,7 +1672,7 @@ mod tests {
16271672 use chain;
16281673 use ln:: PaymentHash ;
16291674 use ln:: features:: { ChannelFeatures , InitFeatures , NodeFeatures } ;
1630- use routing:: gossip:: { P2PGossipSync , NetworkGraph , NetworkUpdate , MAX_EXCESS_BYTES_FOR_RELAY } ;
1675+ use routing:: gossip:: { P2PGossipSync , NetworkGraph , NetworkUpdate , NodeAlias , MAX_EXCESS_BYTES_FOR_RELAY } ;
16311676 use ln:: msgs:: { Init , OptionalField , RoutingMessageHandler , UnsignedNodeAnnouncement , NodeAnnouncement ,
16321677 UnsignedChannelAnnouncement , ChannelAnnouncement , UnsignedChannelUpdate , ChannelUpdate ,
16331678 ReplyChannelRange , QueryChannelRange , QueryShortChannelIds , MAX_VALUE_MSAT } ;
@@ -2731,6 +2776,29 @@ mod tests {
27312776 } ) ;
27322777 assert ! ( result. is_err( ) ) ;
27332778 }
2779+
2780+ #[ test]
2781+ fn displays_node_alias ( ) {
2782+ let format_str_alias = |alias : & str | {
2783+ let mut bytes = [ 0u8 ; 32 ] ;
2784+ bytes[ ..alias. as_bytes ( ) . len ( ) ] . copy_from_slice ( alias. as_bytes ( ) ) ;
2785+ format ! ( "{}" , NodeAlias ( bytes) )
2786+ } ;
2787+
2788+ assert_eq ! ( format_str_alias( "I\u{1F496} LDK! \u{26A1} " ) , "I\u{1F496} LDK! \u{26A1} " ) ;
2789+ assert_eq ! ( format_str_alias( "I\u{1F496} LDK!\0 \u{26A1} " ) , "I\u{1F496} LDK!" ) ;
2790+ assert_eq ! ( format_str_alias( "I\u{1F496} LDK!\t \u{26A1} " ) , "I\u{1F496} LDK!\u{FFFD} \u{26A1} " ) ;
2791+
2792+ let format_bytes_alias = |alias : & [ u8 ] | {
2793+ let mut bytes = [ 0u8 ; 32 ] ;
2794+ bytes[ ..alias. len ( ) ] . copy_from_slice ( alias) ;
2795+ format ! ( "{}" , NodeAlias ( bytes) )
2796+ } ;
2797+
2798+ assert_eq ! ( format_bytes_alias( b"\xFF I <heart> LDK!" ) , "\u{FFFD} I <heart> LDK!" ) ;
2799+ assert_eq ! ( format_bytes_alias( b"\xFF I <heart>\0 LDK!" ) , "\u{FFFD} I <heart>" ) ;
2800+ assert_eq ! ( format_bytes_alias( b"\xFF I <heart>\t LDK!" ) , "\u{FFFD} I <heart>\u{FFFD} LDK!" ) ;
2801+ }
27342802}
27352803
27362804#[ cfg( all( test, feature = "_bench_unstable" ) ) ]
0 commit comments