-
Notifications
You must be signed in to change notification settings - Fork 135
Onion messaging support #68
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 1 commit
93b627b
75af2ed
5e26d46
b9c2b35
4f2dbed
77d81d8
148f914
eb6bd5c
4fa0d14
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -87,48 +87,62 @@ func (hp *HopPayload) Encode(w io.Writer) error { | |
| } | ||
|
|
||
| // Decode unpacks an encoded HopPayload from the passed reader into the target | ||
| // HopPayload. | ||
| func (hp *HopPayload) Decode(r io.Reader) error { | ||
| // HopPayload. tlvGuaranteed should be set to true if the caller only wishes to | ||
| // accept TLV encoded payloads. By doing so, zero-lengt tlv payloads are | ||
| // supported. If set to false, then the function will inspect the first byte to | ||
| // determine the type of payload. | ||
| func DecodeHopPayload(r io.Reader, tlvGuaranteed bool) (*HopPayload, error) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. think you can condense this to: |
||
| bufReader := bufio.NewReader(r) | ||
|
|
||
| // In order to properly parse the payload, we'll need to check the | ||
| // first byte. We'll use a bufio reader to peek at it without consuming | ||
| // it from the buffer. | ||
| var payloadSize uint16 | ||
|
|
||
| hopPayload := &HopPayload{} | ||
|
|
||
| // If we are not sure if this is a TLV or legacy payload, then we need | ||
| // to inspect the first byte to determine the type of payload. The first | ||
| // byte is either a realm (legacy) or the beginning of a var-int | ||
| // encoding the length of the payload (TLV). We'll use a bufio reader to | ||
| // peek at it without consuming it from the buffer. | ||
| peekByte, err := bufReader.Peek(1) | ||
gijswijs marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if err != nil { | ||
| return err | ||
| return nil, fmt.Errorf("peek first payload byte: %w", err) | ||
| } | ||
|
|
||
| var ( | ||
| legacyPayload = isLegacyPayloadByte(peekByte[0]) | ||
| payloadSize uint16 | ||
| ) | ||
| switch { | ||
| case tlvGuaranteed: | ||
| // If we're instructed to only accept TLV payloads, then we set | ||
| // the type accordingly. This allows us to support zero-length | ||
| // TLV payloads. | ||
|
|
||
| hopPayload.Type = PayloadTLV | ||
|
|
||
| if legacyPayload { | ||
| payloadSize = legacyPayloadSize() | ||
| hp.Type = PayloadLegacy | ||
| } else { | ||
| payloadSize, err = tlvPayloadSize(bufReader) | ||
| if err != nil { | ||
| return err | ||
| return nil, err | ||
| } | ||
|
|
||
gijswijs marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| hp.Type = PayloadTLV | ||
| } | ||
| case isLegacyPayloadByte(peekByte[0]): | ||
| // If the first byte indicates that this is a legacy payload, | ||
| // then we set the type accordingly. | ||
| hopPayload.Type = PayloadLegacy | ||
| payloadSize = legacyPayloadSize() | ||
|
|
||
| // Now that we know the payload size, we'll create a new buffer to | ||
| // read it out in full. | ||
| // | ||
| // TODO(roasbeef): can avoid all these copies | ||
| hp.Payload = make([]byte, payloadSize) | ||
| if _, err := io.ReadFull(bufReader, hp.Payload[:]); err != nil { | ||
| return err | ||
| default: | ||
| // Otherwise, we set the type to TLV. | ||
| hopPayload.Type = PayloadTLV | ||
|
|
||
| payloadSize, err = tlvPayloadSize(bufReader) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| } | ||
| if _, err := io.ReadFull(bufReader, hp.HMAC[:]); err != nil { | ||
| return err | ||
|
|
||
| err = readPayloadAndHMAC(hopPayload, bufReader, payloadSize) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| return nil | ||
| return hopPayload, nil | ||
| } | ||
|
|
||
| // HopData attempts to extract a set of forwarding instructions from the target | ||
|
|
@@ -146,6 +160,26 @@ func (hp *HopPayload) HopData() (*HopData, error) { | |
| return nil, nil | ||
| } | ||
|
|
||
| // readPayloadAndHMAC reads the payload and HMAC from the reader into the | ||
| // HopPayload. | ||
| func readPayloadAndHMAC(hp *HopPayload, r io.Reader, payloadSize uint16) error { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this was useful when there were multiple call sites but now there is only one. so let's keep this logic in the single constructor |
||
| // Now that we know the payload size, we'll create a new buffer to read | ||
| // it out in full. | ||
| hp.Payload = make([]byte, payloadSize) | ||
|
|
||
| _, err := io.ReadFull(r, hp.Payload) | ||
| if err != nil { | ||
| return fmt.Errorf("%w: %w", ErrIOReadFull, err) | ||
| } | ||
|
|
||
| _, err = io.ReadFull(r, hp.HMAC[:]) | ||
| if err != nil { | ||
| return fmt.Errorf("%w: %w", ErrIOReadFull, err) | ||
| } | ||
gijswijs marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| return nil | ||
| } | ||
|
|
||
| // tlvPayloadSize uses the passed reader to extract the payload length encoded | ||
| // as a var-int. | ||
| func tlvPayloadSize(r io.Reader) (uint16, error) { | ||
|
|
@@ -314,8 +348,12 @@ func legacyNumBytes() int { | |
| return LegacyHopDataSize | ||
| } | ||
|
|
||
| // isLegacyPayload returns true if the given byte is equal to the 0x00 byte | ||
| // which indicates that the payload should be decoded as a legacy payload. | ||
| // isLegacyPayloadByte determines if the first byte of a hop payload indicates | ||
| // that it is a legacy payload. The first byte of a legacy payload will always | ||
| // be 0x00, as this is the realm. For TLV payloads, the first byte is a | ||
| // var-int encoding the length of the payload. A TLV stream can be empty, in | ||
| // which case its length is 0, which is also encoded as a 0x00 byte. This | ||
| // creates an ambiguity between a legacy payload and an empty TLV payload. | ||
gijswijs marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| func isLegacyPayloadByte(b byte) bool { | ||
| return b == 0x00 | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comment starts with incorrect name