189 lines
3.7 KiB
Go
189 lines
3.7 KiB
Go
package jess
|
|
|
|
import (
|
|
"errors"
|
|
|
|
"github.com/safing/structures/container"
|
|
)
|
|
|
|
/*
|
|
### Wire Format Version 1
|
|
|
|
- Wire Format Version: varint
|
|
- Flags: varint
|
|
- 1: Setup Msg (includes Version and Tools)
|
|
- 2: Sending Keys
|
|
- 4: Apply Keys
|
|
- Version: varint (if Setup Msg)
|
|
- SuiteID: byte block (if Setup Msg)
|
|
- Keys:
|
|
- Amount: varint
|
|
- IDs/Values: byte blocks
|
|
- Nonce: byte block
|
|
- Data: byte block
|
|
- MAC: byte block
|
|
*/
|
|
|
|
// ErrIncompatibleWireFormatVersion is returned when an incompatible wire format is encountered.
|
|
var ErrIncompatibleWireFormatVersion = errors.New("incompatible wire format version")
|
|
|
|
// ToWire serializes to letter for sending it over a network connection.
|
|
func (letter *Letter) ToWire() (*container.Container, error) {
|
|
c := container.New()
|
|
|
|
// Wire Format Version: varint
|
|
c.AppendNumber(1)
|
|
|
|
// Flags: varint
|
|
// - 1: Setup Msg (includes Version and Tools)
|
|
// - 2: Sending Keys
|
|
// - 4: Apply Keys
|
|
var flags uint64
|
|
if letter.Version > 0 {
|
|
flags |= 1
|
|
}
|
|
if len(letter.Keys) > 0 {
|
|
flags |= 2
|
|
}
|
|
if letter.ApplyKeys {
|
|
flags |= 4
|
|
}
|
|
c.AppendNumber(flags)
|
|
|
|
if letter.Version > 0 {
|
|
// Version: varint (if Setup Msg)
|
|
c.AppendNumber(uint64(letter.Version))
|
|
|
|
// SuiteID: byte block (if Setup Msg)
|
|
c.AppendAsBlock([]byte(letter.SuiteID))
|
|
}
|
|
|
|
if len(letter.Keys) > 0 {
|
|
// Keys:
|
|
// - Amount: varint
|
|
// - IDs/Values: byte blocks
|
|
c.AppendInt(len(letter.Keys))
|
|
for _, seal := range letter.Keys {
|
|
c.AppendAsBlock([]byte(seal.ID))
|
|
c.AppendAsBlock(seal.Value)
|
|
}
|
|
}
|
|
|
|
// Nonce: byte block
|
|
c.AppendAsBlock(letter.Nonce)
|
|
|
|
// Data: byte block
|
|
c.AppendAsBlock(letter.Data)
|
|
|
|
// MAC: byte block
|
|
c.AppendAsBlock(letter.Mac)
|
|
|
|
// debugging:
|
|
// fmt.Printf("%+v\n", c.CompileData())
|
|
|
|
return c, nil
|
|
}
|
|
|
|
// LetterFromWireData is a relay to LetterFromWire to quickly fix import issues of godep.
|
|
//
|
|
// Deprecated: Please use LetterFromWire with a fresh container directly.
|
|
func LetterFromWireData(data []byte) (*Letter, error) {
|
|
return LetterFromWire(container.New(data))
|
|
}
|
|
|
|
// LetterFromWire parses a letter sent over a network connection.
|
|
func LetterFromWire(c *container.Container) (*Letter, error) {
|
|
letter := &Letter{}
|
|
|
|
// Wire Format Version: varint
|
|
wireFormatVersion, err := c.GetNextN8()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if wireFormatVersion != 1 {
|
|
return nil, ErrIncompatibleWireFormatVersion
|
|
}
|
|
|
|
// Flags: varint
|
|
// - 1: Setup Msg (includes Version and Tools)
|
|
// - 2: Sending Keys
|
|
// - 4: Apply Keys
|
|
var (
|
|
setupMsg bool
|
|
sendingKeys bool
|
|
)
|
|
flags, err := c.GetNextN64()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if flags&1 > 0 {
|
|
setupMsg = true
|
|
}
|
|
if flags&2 > 0 {
|
|
sendingKeys = true
|
|
}
|
|
if flags&4 > 0 {
|
|
letter.ApplyKeys = true
|
|
}
|
|
|
|
if setupMsg {
|
|
// Version: varint (if Setup Msg)
|
|
n, err := c.GetNextN8()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
letter.Version = n
|
|
|
|
// SuiteID: byte block (if Setup Msg)
|
|
suiteID, err := c.GetNextBlock()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
letter.SuiteID = string(suiteID)
|
|
}
|
|
|
|
if sendingKeys {
|
|
// Keys:
|
|
// - Amount: varint
|
|
// - IDs/Values: byte blocks
|
|
n, err := c.GetNextN8()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
letter.Keys = make([]*Seal, n)
|
|
for i := 0; i < len(letter.Keys); i++ {
|
|
signetID, err := c.GetNextBlock()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
sealValue, err := c.GetNextBlock()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
letter.Keys[i] = &Seal{
|
|
ID: string(signetID),
|
|
Value: sealValue,
|
|
}
|
|
}
|
|
}
|
|
|
|
// Nonce: byte block
|
|
letter.Nonce, err = c.GetNextBlock()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Data: byte block
|
|
letter.Data, err = c.GetNextBlock()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// MAC: byte block
|
|
letter.Mac, err = c.GetNextBlock()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return letter, nil
|
|
}
|