2
0
mirror of https://github.com/edouardparis/lntop synced 2024-11-16 00:12:44 +00:00
lntop/vendor/gopkg.in/macaroon.v2/packet-v1.go
2019-03-15 17:02:16 +01:00

134 lines
3.2 KiB
Go

package macaroon
import (
"bytes"
"fmt"
)
// field names, as defined in libmacaroons
const (
fieldNameLocation = "location"
fieldNameIdentifier = "identifier"
fieldNameSignature = "signature"
fieldNameCaveatId = "cid"
fieldNameVerificationId = "vid"
fieldNameCaveatLocation = "cl"
)
// maxPacketV1Len is the maximum allowed length of a packet in the v1 macaroon
// serialization format.
const maxPacketV1Len = 0xffff
// The original macaroon binary encoding is made from a sequence
// of "packets", each of which has a field name and some data.
// The encoding is:
//
// - four ascii hex digits holding the entire packet size (including
// the digits themselves).
//
// - the field name, followed by an ascii space.
//
// - the raw data
//
// - a newline (\n) character
//
// The packet struct below holds a reference into Macaroon.data.
type packetV1 struct {
// ftype holds the field name of the packet.
fieldName []byte
// data holds the packet's data.
data []byte
// len holds the total length in bytes
// of the packet, including any header.
totalLen int
}
// parsePacket parses the packet at the start of the
// given data.
func parsePacketV1(data []byte) (packetV1, error) {
if len(data) < 6 {
return packetV1{}, fmt.Errorf("packet too short")
}
plen, ok := parseSizeV1(data)
if !ok {
return packetV1{}, fmt.Errorf("cannot parse size")
}
if plen > len(data) {
return packetV1{}, fmt.Errorf("packet size too big")
}
if plen < 4 {
return packetV1{}, fmt.Errorf("packet size too small")
}
data = data[4:plen]
i := bytes.IndexByte(data, ' ')
if i <= 0 {
return packetV1{}, fmt.Errorf("cannot parse field name")
}
fieldName := data[0:i]
if data[len(data)-1] != '\n' {
return packetV1{}, fmt.Errorf("no terminating newline found")
}
return packetV1{
fieldName: fieldName,
data: data[i+1 : len(data)-1],
totalLen: plen,
}, nil
}
// appendPacketV1 appends a packet with the given field name
// and data to the given buffer. If the field and data were
// too long to be encoded, it returns nil, false; otherwise
// it returns the appended buffer.
func appendPacketV1(buf []byte, field string, data []byte) ([]byte, bool) {
plen := packetV1Size(field, data)
if plen > maxPacketV1Len {
return nil, false
}
buf = appendSizeV1(buf, plen)
buf = append(buf, field...)
buf = append(buf, ' ')
buf = append(buf, data...)
buf = append(buf, '\n')
return buf, true
}
func packetV1Size(field string, data []byte) int {
return 4 + len(field) + 1 + len(data) + 1
}
var hexDigits = []byte("0123456789abcdef")
func appendSizeV1(data []byte, size int) []byte {
return append(data,
hexDigits[size>>12],
hexDigits[(size>>8)&0xf],
hexDigits[(size>>4)&0xf],
hexDigits[size&0xf],
)
}
func parseSizeV1(data []byte) (int, bool) {
d0, ok0 := asciiHex(data[0])
d1, ok1 := asciiHex(data[1])
d2, ok2 := asciiHex(data[2])
d3, ok3 := asciiHex(data[3])
return d0<<12 + d1<<8 + d2<<4 + d3, ok0 && ok1 && ok2 && ok3
}
func asciiHex(b byte) (int, bool) {
switch {
case b >= '0' && b <= '9':
return int(b) - '0', true
case b >= 'a' && b <= 'f':
return int(b) - 'a' + 0xa, true
}
return 0, false
}
func isASCIIHex(b byte) bool {
_, ok := asciiHex(b)
return ok
}