]> git.bitcoin.ninja Git - rust-lightning/blob - lightning/src/offers/parse.rs
Add some no-exporting of more offers code
[rust-lightning] / lightning / src / offers / parse.rs
1 // This file is Copyright its original authors, visible in version control
2 // history.
3 //
4 // This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
5 // or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
7 // You may not use this file except in accordance with one or both of these
8 // licenses.
9
10 //! Parsing and formatting for bech32 message encoding.
11
12 use bitcoin::bech32;
13 use bitcoin::secp256k1;
14 use core::convert::TryFrom;
15 use crate::io;
16 use crate::ln::msgs::DecodeError;
17 use crate::util::ser::SeekReadable;
18
19 use crate::prelude::*;
20
21 #[cfg(not(fuzzing))]
22 pub(super) use sealed::Bech32Encode;
23
24 #[cfg(fuzzing)]
25 pub use sealed::Bech32Encode;
26
27 mod sealed {
28         use bitcoin::bech32;
29         use bitcoin::bech32::{FromBase32, ToBase32};
30         use core::convert::TryFrom;
31         use core::fmt;
32         use super::ParseError;
33
34         use crate::prelude::*;
35
36         /// Indicates a message can be encoded using bech32.
37         pub trait Bech32Encode: AsRef<[u8]> + TryFrom<Vec<u8>, Error=ParseError> {
38                 /// Human readable part of the message's bech32 encoding.
39                 const BECH32_HRP: &'static str;
40
41                 /// Parses a bech32-encoded message into a TLV stream.
42                 fn from_bech32_str(s: &str) -> Result<Self, ParseError> {
43                         // Offer encoding may be split by '+' followed by optional whitespace.
44                         let encoded = match s.split('+').skip(1).next() {
45                                 Some(_) => {
46                                         for chunk in s.split('+') {
47                                                 let chunk = chunk.trim_start();
48                                                 if chunk.is_empty() || chunk.contains(char::is_whitespace) {
49                                                         return Err(ParseError::InvalidContinuation);
50                                                 }
51                                         }
52
53                                         let s: String = s.chars().filter(|c| *c != '+' && !c.is_whitespace()).collect();
54                                         Bech32String::Owned(s)
55                                 },
56                                 None => Bech32String::Borrowed(s),
57                         };
58
59                         let (hrp, data) = bech32::decode_without_checksum(encoded.as_ref())?;
60
61                         if hrp != Self::BECH32_HRP {
62                                 return Err(ParseError::InvalidBech32Hrp);
63                         }
64
65                         let data = Vec::<u8>::from_base32(&data)?;
66                         Self::try_from(data)
67                 }
68
69                 /// Formats the message using bech32-encoding.
70                 fn fmt_bech32_str(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
71                         bech32::encode_without_checksum_to_fmt(f, Self::BECH32_HRP, self.as_ref().to_base32())
72                                 .expect("HRP is invalid").unwrap();
73
74                         Ok(())
75                 }
76         }
77
78         // Used to avoid copying a bech32 string not containing the continuation character (+).
79         enum Bech32String<'a> {
80                 Borrowed(&'a str),
81                 Owned(String),
82         }
83
84         impl<'a> AsRef<str> for Bech32String<'a> {
85                 fn as_ref(&self) -> &str {
86                         match self {
87                                 Bech32String::Borrowed(s) => s,
88                                 Bech32String::Owned(s) => s,
89                         }
90                 }
91         }
92 }
93
94 /// A wrapper for reading a message as a TLV stream `T` from a byte sequence, while still
95 /// maintaining ownership of the bytes for later use.
96 pub(super) struct ParsedMessage<T: SeekReadable> {
97         pub bytes: Vec<u8>,
98         pub tlv_stream: T,
99 }
100
101 impl<T: SeekReadable> TryFrom<Vec<u8>> for ParsedMessage<T> {
102         type Error = DecodeError;
103
104         fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
105                 let mut cursor = io::Cursor::new(bytes);
106                 let tlv_stream: T = SeekReadable::read(&mut cursor)?;
107
108                 // Ensure that there are no more TLV records left to parse.
109                 if cursor.position() < cursor.get_ref().len() as u64 {
110                         return Err(DecodeError::InvalidValue);
111                 }
112
113                 let bytes = cursor.into_inner();
114                 Ok(Self { bytes, tlv_stream })
115         }
116 }
117
118 /// Error when parsing a bech32 encoded message using [`str::parse`].
119 ///
120 /// This is not exported to bindings users as its name conflicts with the BOLT 11 ParseError type.
121 #[derive(Debug, PartialEq)]
122 pub enum ParseError {
123         /// The bech32 encoding does not conform to the BOLT 12 requirements for continuing messages
124         /// across multiple parts (i.e., '+' followed by whitespace).
125         InvalidContinuation,
126         /// The bech32 encoding's human-readable part does not match what was expected for the message
127         /// being parsed.
128         InvalidBech32Hrp,
129         /// The string could not be bech32 decoded.
130         Bech32(/// This is not exported to bindings users as the details don't matter much
131                 bech32::Error),
132         /// The bech32 decoded string could not be decoded as the expected message type.
133         Decode(DecodeError),
134         /// The parsed message has invalid semantics.
135         InvalidSemantics(SemanticError),
136         /// The parsed message has an invalid signature.
137         InvalidSignature(secp256k1::Error),
138 }
139
140 /// Error when interpreting a TLV stream as a specific type.
141 ///
142 /// This is not exported to bindings users as its name conflicts with the BOLT 11 SemanticError type.
143 #[derive(Debug, PartialEq)]
144 pub enum SemanticError {
145         /// The current [`std::time::SystemTime`] is past the offer or invoice's expiration.
146         AlreadyExpired,
147         /// The provided chain hash does not correspond to a supported chain.
148         UnsupportedChain,
149         /// A chain was provided but was not expected.
150         UnexpectedChain,
151         /// An amount was expected but was missing.
152         MissingAmount,
153         /// The amount exceeded the total bitcoin supply.
154         InvalidAmount,
155         /// An amount was provided but was not sufficient in value.
156         InsufficientAmount,
157         /// An amount was provided but was not expected.
158         UnexpectedAmount,
159         /// A currency was provided that is not supported.
160         UnsupportedCurrency,
161         /// A feature was required but is unknown.
162         UnknownRequiredFeatures,
163         /// Features were provided but were not expected.
164         UnexpectedFeatures,
165         /// A required description was not provided.
166         MissingDescription,
167         /// A signing pubkey was not provided.
168         MissingSigningPubkey,
169         /// A signing pubkey was provided but a different one was expected.
170         InvalidSigningPubkey,
171         /// A signing pubkey was provided but was not expected.
172         UnexpectedSigningPubkey,
173         /// A quantity was expected but was missing.
174         MissingQuantity,
175         /// An unsupported quantity was provided.
176         InvalidQuantity,
177         /// A quantity or quantity bounds was provided but was not expected.
178         UnexpectedQuantity,
179         /// Metadata could not be used to verify the offers message.
180         InvalidMetadata,
181         /// Metadata was provided but was not expected.
182         UnexpectedMetadata,
183         /// Payer metadata was expected but was missing.
184         MissingPayerMetadata,
185         /// A payer id was expected but was missing.
186         MissingPayerId,
187         /// Blinded paths were expected but were missing.
188         MissingPaths,
189         /// The blinded payinfo given does not match the number of blinded path hops.
190         InvalidPayInfo,
191         /// An invoice creation time was expected but was missing.
192         MissingCreationTime,
193         /// An invoice payment hash was expected but was missing.
194         MissingPaymentHash,
195         /// A signature was expected but was missing.
196         MissingSignature,
197 }
198
199 impl From<bech32::Error> for ParseError {
200         fn from(error: bech32::Error) -> Self {
201                 Self::Bech32(error)
202         }
203 }
204
205 impl From<DecodeError> for ParseError {
206         fn from(error: DecodeError) -> Self {
207                 Self::Decode(error)
208         }
209 }
210
211 impl From<SemanticError> for ParseError {
212         fn from(error: SemanticError) -> Self {
213                 Self::InvalidSemantics(error)
214         }
215 }
216
217 impl From<secp256k1::Error> for ParseError {
218         fn from(error: secp256k1::Error) -> Self {
219                 Self::InvalidSignature(error)
220         }
221 }