@@ -56,11 +56,12 @@ use bitcoin::secp256k1::schnorr::Signature;
56
56
use core:: convert:: TryFrom ;
57
57
use io;
58
58
use ln:: features:: OfferFeatures ;
59
+ use ln:: msgs:: DecodeError ;
59
60
use offers:: merkle:: { SignatureTlvStream , SignatureTlvStreamRef , self } ;
60
61
use offers:: offer:: { Amount , Offer , OfferContents , OfferTlvStream , OfferTlvStreamRef } ;
61
62
use offers:: parse:: { ParseError , SemanticError } ;
62
63
use offers:: payer:: { PayerContents , PayerTlvStream , PayerTlvStreamRef } ;
63
- use util:: ser:: { HighZeroBytesDroppedBigSize , Readable , WithoutLength , Writeable , Writer } ;
64
+ use util:: ser:: { HighZeroBytesDroppedBigSize , SeekReadable , WithoutLength , Writeable , Writer } ;
64
65
65
66
use prelude:: * ;
66
67
@@ -341,12 +342,19 @@ impl TryFrom<Vec<u8>> for InvoiceRequest {
341
342
type Error = ParseError ;
342
343
343
344
fn try_from ( bytes : Vec < u8 > ) -> Result < Self , Self :: Error > {
344
- let tlv_stream: FullInvoiceRequestTlvStream = Readable :: read ( & mut & bytes[ ..] ) ?;
345
+ let mut cursor = io:: Cursor :: new ( bytes) ;
346
+ let tlv_stream: FullInvoiceRequestTlvStream = SeekReadable :: read ( & mut cursor) ?;
347
+
348
+ if cursor. position ( ) < cursor. get_ref ( ) . len ( ) as u64 {
349
+ return Err ( ParseError :: Decode ( DecodeError :: InvalidValue ) ) ;
350
+ }
351
+
352
+ let bytes = cursor. into_inner ( ) ;
345
353
InvoiceRequest :: try_from ( ( bytes, tlv_stream) )
346
354
}
347
355
}
348
356
349
- tlv_stream ! ( InvoiceRequestTlvStream , InvoiceRequestTlvStreamRef , {
357
+ tlv_stream ! ( InvoiceRequestTlvStream , InvoiceRequestTlvStreamRef , 80 .. 160 , {
350
358
( 80 , chain: ChainHash ) ,
351
359
( 82 , amount: ( u64 , HighZeroBytesDroppedBigSize ) ) ,
352
360
( 84 , features: OfferFeatures ) ,
@@ -360,6 +368,17 @@ type ParsedInvoiceRequest = (Vec<u8>, FullInvoiceRequestTlvStream);
360
368
type FullInvoiceRequestTlvStream =
361
369
( PayerTlvStream , OfferTlvStream , InvoiceRequestTlvStream , SignatureTlvStream ) ;
362
370
371
+ impl SeekReadable for FullInvoiceRequestTlvStream {
372
+ fn read < R : io:: Read + io:: Seek > ( r : & mut R ) -> Result < Self , DecodeError > {
373
+ let payer = SeekReadable :: read ( r) ?;
374
+ let offer = SeekReadable :: read ( r) ?;
375
+ let invoice_request = SeekReadable :: read ( r) ?;
376
+ let signature = SeekReadable :: read ( r) ?;
377
+
378
+ Ok ( ( payer, offer, invoice_request, signature) )
379
+ }
380
+ }
381
+
363
382
type PartialInvoiceRequestTlvStream = ( PayerTlvStream , OfferTlvStream , InvoiceRequestTlvStream ) ;
364
383
365
384
type PartialInvoiceRequestTlvStreamRef < ' a > = (
@@ -448,3 +467,40 @@ impl TryFrom<PartialInvoiceRequestTlvStream> for InvoiceRequestContents {
448
467
} )
449
468
}
450
469
}
470
+
471
+ #[ cfg( test) ]
472
+ mod tests {
473
+ use super :: InvoiceRequest ;
474
+
475
+ use bitcoin:: secp256k1:: { KeyPair , Secp256k1 , SecretKey } ;
476
+ use core:: convert:: TryFrom ;
477
+ use ln:: msgs:: DecodeError ;
478
+ use offers:: offer:: OfferBuilder ;
479
+ use offers:: parse:: ParseError ;
480
+ use util:: ser:: { BigSize , Writeable } ;
481
+
482
+ #[ test]
483
+ fn fails_parsing_invoice_request_with_extra_tlv_records ( ) {
484
+ let secp_ctx = Secp256k1 :: new ( ) ;
485
+ let keys = KeyPair :: from_secret_key ( & secp_ctx, & SecretKey :: from_slice ( & [ 42 ; 32 ] ) . unwrap ( ) ) ;
486
+ let invoice_request = OfferBuilder :: new ( "foo" . into ( ) , keys. public_key ( ) )
487
+ . build ( )
488
+ . unwrap ( )
489
+ . request_invoice ( keys. public_key ( ) )
490
+ . build ( )
491
+ . unwrap ( )
492
+ . sign ( |digest| secp_ctx. sign_schnorr_no_aux_rand ( digest, & keys) )
493
+ . unwrap ( ) ;
494
+
495
+ let mut encoded_invoice_request = Vec :: new ( ) ;
496
+ invoice_request. write ( & mut encoded_invoice_request) . unwrap ( ) ;
497
+ BigSize ( 1002 ) . write ( & mut encoded_invoice_request) . unwrap ( ) ;
498
+ BigSize ( 32 ) . write ( & mut encoded_invoice_request) . unwrap ( ) ;
499
+ [ 42u8 ; 32 ] . write ( & mut encoded_invoice_request) . unwrap ( ) ;
500
+
501
+ match InvoiceRequest :: try_from ( encoded_invoice_request) {
502
+ Ok ( _) => panic ! ( "expected error" ) ,
503
+ Err ( e) => assert_eq ! ( e, ParseError :: Decode ( DecodeError :: InvalidValue ) ) ,
504
+ }
505
+ }
506
+ }
0 commit comments