19d7d74ed6111fd6ddc9fef9d7410a8a47b43354
[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::bech32::{FromBase32, ToBase32};
14 use core::convert::TryFrom;
15 use core::fmt;
16 use crate::io;
17 use crate::ln::msgs::DecodeError;
18 use crate::util::ser::SeekReadable;
19
20 use crate::prelude::*;
21
22 /// Indicates a message can be encoded using bech32.
23 pub(crate) trait Bech32Encode: AsRef<[u8]> + TryFrom<Vec<u8>, Error=ParseError> {
24         /// Human readable part of the message's bech32 encoding.
25         const BECH32_HRP: &'static str;
26
27         /// Parses a bech32-encoded message into a TLV stream.
28         fn from_bech32_str(s: &str) -> Result<Self, ParseError> {
29                 // Offer encoding may be split by '+' followed by optional whitespace.
30                 let encoded = match s.split('+').skip(1).next() {
31                         Some(_) => {
32                                 for chunk in s.split('+') {
33                                         let chunk = chunk.trim_start();
34                                         if chunk.is_empty() || chunk.contains(char::is_whitespace) {
35                                                 return Err(ParseError::InvalidContinuation);
36                                         }
37                                 }
38
39                                 let s = s.chars().filter(|c| *c != '+' && !c.is_whitespace()).collect::<String>();
40                                 Bech32String::Owned(s)
41                         },
42                         None => Bech32String::Borrowed(s),
43                 };
44
45                 let (hrp, data) = bech32::decode_without_checksum(encoded.as_ref())?;
46
47                 if hrp != Self::BECH32_HRP {
48                         return Err(ParseError::InvalidBech32Hrp);
49                 }
50
51                 let data = Vec::<u8>::from_base32(&data)?;
52                 Self::try_from(data)
53         }
54
55         /// Formats the message using bech32-encoding.
56         fn fmt_bech32_str(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
57                 bech32::encode_without_checksum_to_fmt(f, Self::BECH32_HRP, self.as_ref().to_base32())
58                         .expect("HRP is invalid").unwrap();
59
60                 Ok(())
61         }
62 }
63
64 // Used to avoid copying a bech32 string not containing the continuation character (+).
65 enum Bech32String<'a> {
66         Borrowed(&'a str),
67         Owned(String),
68 }
69
70 impl<'a> AsRef<str> for Bech32String<'a> {
71         fn as_ref(&self) -> &str {
72                 match self {
73                         Bech32String::Borrowed(s) => s,
74                         Bech32String::Owned(s) => s,
75                 }
76         }
77 }
78
79 /// A wrapper for reading a message as a TLV stream `T` from a byte sequence, while still
80 /// maintaining ownership of the bytes for later use.
81 pub(crate) struct ParsedMessage<T: SeekReadable> {
82         pub bytes: Vec<u8>,
83         pub tlv_stream: T,
84 }
85
86 impl<T: SeekReadable> TryFrom<Vec<u8>> for ParsedMessage<T> {
87         type Error = DecodeError;
88
89         fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
90                 let mut cursor = io::Cursor::new(bytes);
91                 let tlv_stream: T = SeekReadable::read(&mut cursor)?;
92
93                 // Ensure that there are no more TLV records left to parse.
94                 if cursor.position() < cursor.get_ref().len() as u64 {
95                         return Err(DecodeError::InvalidValue);
96                 }
97
98                 let bytes = cursor.into_inner();
99                 Ok(Self { bytes, tlv_stream })
100         }
101 }
102
103 /// Error when parsing a bech32 encoded message using [`str::parse`].
104 #[derive(Debug, PartialEq)]
105 pub enum ParseError {
106         /// The bech32 encoding does not conform to the BOLT 12 requirements for continuing messages
107         /// across multiple parts (i.e., '+' followed by whitespace).
108         InvalidContinuation,
109         /// The bech32 encoding's human-readable part does not match what was expected for the message
110         /// being parsed.
111         InvalidBech32Hrp,
112         /// The string could not be bech32 decoded.
113         Bech32(bech32::Error),
114         /// The bech32 decoded string could not be decoded as the expected message type.
115         Decode(DecodeError),
116         /// The parsed message has invalid semantics.
117         InvalidSemantics(SemanticError),
118 }
119
120 /// Error when interpreting a TLV stream as a specific type.
121 #[derive(Debug, PartialEq)]
122 pub enum SemanticError {
123         /// An amount was expected but was missing.
124         MissingAmount,
125         /// The amount exceeded the total bitcoin supply.
126         InvalidAmount,
127         /// A currency was provided that is not supported.
128         UnsupportedCurrency,
129         /// A required description was not provided.
130         MissingDescription,
131         /// A signing pubkey was not provided.
132         MissingSigningPubkey,
133         /// An unsupported quantity was provided.
134         InvalidQuantity,
135 }
136
137 impl From<bech32::Error> for ParseError {
138         fn from(error: bech32::Error) -> Self {
139                 Self::Bech32(error)
140         }
141 }
142
143 impl From<DecodeError> for ParseError {
144         fn from(error: DecodeError) -> Self {
145                 Self::Decode(error)
146         }
147 }
148
149 impl From<SemanticError> for ParseError {
150         fn from(error: SemanticError) -> Self {
151                 Self::InvalidSemantics(error)
152         }
153 }