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 }