package jess import ( "errors" "github.com/safing/portbase/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) - Tools: (if Setup Msg) - Amount: varint - Names: byte blocks - Keys: - Amount: varint - IDs/Values: byte blocks - Nonce: byte block - Data: byte block - MAC: byte block */ var ( // ErrIncompatibleWireFormatVersion is returned when an incompatible wire format is encountered. 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)) // Tools: (if Setup Msg) // - Amount: varint // - Names: byte blocks c.AppendInt(len(letter.Tools)) for _, toolName := range letter.Tools { c.AppendAsBlock([]byte(toolName)) } } 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 } // 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 // Tools: (if Setup Msg) // - Amount: varint // - Names: byte blocks n, err = c.GetNextN8() if err != nil { return nil, err } letter.Tools = make([]string, n) for i := 0; i < len(letter.Tools); i++ { toolName, err := c.GetNextBlock() if err != nil { return nil, err } letter.Tools[i] = string(toolName) } } 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 }