Documentation
¶
Overview ¶
Package cotlib implements the Cursor on Target (CoT) protocol for Go.
The package provides data structures and utilities for parsing and generating CoT messages, as well as a comprehensive type catalog system for working with CoT type codes.
Type Catalog ¶
The type catalog system provides a way to work with CoT type codes and their metadata. Each type code (e.g., "a-f-G-E-X-N") has associated metadata:
- Full Name: A hierarchical name (e.g., "Gnd/Equip/Nbc Equipment")
- Description: A human-readable description (e.g., "NBC EQUIPMENT")
The catalog supports several operations:
- Looking up metadata for a specific type code
- Searching for types by description or full name
- Validating type codes
- Registering custom type codes
Example usage:
// Look up type metadata
fullName, err := cotlib.GetTypeFullName("a-f-G-E-X-N")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Full name: %s\n", fullName)
// Search for types
types := cotlib.FindTypesByDescription("NBC")
for _, t := range types {
fmt.Printf("Found type: %s (%s)\n", t.Name, t.Description)
}
Thread Safety ¶
All operations on the type catalog are thread-safe. The catalog uses internal synchronization to ensure safe concurrent access.
Custom Types ¶
Applications can register custom type codes using RegisterCoTType. These custom types must follow the standard CoT type format and will be validated before registration.
For more information about CoT types and their format, see: https://www.mitre.org/sites/default/files/pdf/09_4937.pdf
Security features include:
- XML parsing restrictions to prevent XXE attacks
- Input validation on all fields
- Strict coordinate range enforcement
- Time field validation to prevent time-based attacks
- Secure logging practices
- Detail extension isolation
For more information about CoT, see:
- https://apps.dtic.mil/sti/citations/ADA637348 (Developer Guide)
- https://www.mitre.org/sites/default/files/pdf/09_4937.pdf (Message Router Guide)
- http://cot.mitre.org
The package follows these design principles:
- High cohesion: focused on CoT event parsing and serialization
- Low coupling: separated concerns for expansions and transport
- Composition over inheritance: nested sub-structures for detail fields
- Full schema coverage: implements Event.xsd with example extensions
- Secure by design: validates inputs and prevents common attacks
Example (TypePredicates) ¶
Example_typePredicates demonstrates using type predicates
package main
import (
"fmt"
"github.com/NERVsystems/cotlib"
)
func main() {
// Create some example events
events := []*cotlib.Event{
{Type: "a-f-G-U-C"}, // Friendly ground combat unit
{Type: "a-h-A-M-F"}, // Hostile fixed wing aircraft
{Type: "b-d-c-n-r"}, // NBC radiation detection
{Type: "t-s-i-e"}, // ISR EO tasking
}
// Test various predicates
predicates := []string{"atom", "friend", "hostile", "ground", "air"}
for _, evt := range events {
fmt.Printf("\nEvent type: %s\n", evt.Type)
for _, pred := range predicates {
if evt.Is(pred) {
fmt.Printf(" Matches predicate: %s\n", pred)
}
}
}
}
Output: Event type: a-f-G-U-C Matches predicate: atom Matches predicate: friend Matches predicate: ground Event type: a-h-A-M-F Matches predicate: atom Matches predicate: hostile Matches predicate: air Event type: b-d-c-n-r Matches predicate: atom Event type: t-s-i-e Matches predicate: atom
Index ¶
- Constants
- Variables
- func FindTypes(query string) []cottypes.Type
- func FindTypesByDescription(desc string) []cottypes.Type
- func FindTypesByFullName(name string) []cottypes.Type
- func GetTypeDescription(name string) (string, error)
- func GetTypeFullName(name string) (string, error)
- func LoadCoTTypesFromFile(path string) error
- func LookupType(name string) (cottypes.Type, bool)
- func RegisterAllCoTTypes() error
- func RegisterCoTType(name string)
- func RegisterCoTTypesFromFile(filename string) error
- func RegisterCoTTypesFromReader(r io.Reader) error
- func RegisterCoTTypesFromXMLContent(xmlContent string) error
- func ReleaseEvent(e *Event)
- func SetLogger(l *slog.Logger)
- func SetMaxValueLen(max int64)
- func ValidateLatLon(lat, lon float64) error
- func ValidateType(typ string) error
- func ValidateUID(uid string) error
- func WithLogger(ctx context.Context, l *slog.Logger) context.Context
- type CoTTime
- func (t CoTTime) MarshalXML(e *xml.Encoder, start xml.StartElement) error
- func (t CoTTime) MarshalXMLAttr(name xml.Name) (xml.Attr, error)
- func (t CoTTime) Time() time.Time
- func (t *CoTTime) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
- func (t *CoTTime) UnmarshalXMLAttr(attr xml.Attr) error
- type Contact
- type Detail
- type Event
- type Group
- type Link
- type Point
Examples ¶
Constants ¶
const ( // CotTimeFormat is the standard time format for CoT messages (Zulu time, no offset) // Format: "2006-01-02T15:04:05Z" (UTC without timezone offset) CotTimeFormat = "2006-01-02T15:04:05Z" )
Security limits for XML parsing and validation
Variables ¶
var ( ErrInvalidInput = fmt.Errorf("invalid input") ErrInvalidLatitude = fmt.Errorf("invalid latitude") ErrInvalidUID = fmt.Errorf("invalid UID") )
Error sentinels for validation
Functions ¶
func FindTypesByDescription ¶
FindTypesByDescription searches for types matching the given description. The search is case-insensitive and matches partial descriptions.
For example:
- "NBC" finds all types containing "NBC" in their description
- "EQUIPMENT" finds all equipment-related types
- "COMBAT" finds all combat-related types
This is useful for building search interfaces and type discovery tools. Returns an empty slice if no matches are found.
Example ¶
package main
import (
"fmt"
"sort"
"github.com/NERVsystems/cotlib"
)
func main() {
types := cotlib.FindTypesByDescription("NBC EQUIPMENT")
// Sort by name for consistent output
sort.Slice(types, func(i, j int) bool {
return types[i].Name < types[j].Name
})
for _, t := range types {
fmt.Printf("Found type: %s (%s)\n", t.Name, t.Description)
}
}
Output: Found type: a-f-G-E-X-N (NBC EQUIPMENT) Found type: a-h-G-E-X-N (NBC EQUIPMENT) Found type: a-n-G-E-X-N (NBC EQUIPMENT) Found type: a-u-G-E-X-N (NBC EQUIPMENT)
func FindTypesByFullName ¶
FindTypesByFullName searches for types matching the given full name. The search is case-insensitive and matches partial names.
For example:
- "Nbc Equipment" finds all NBC equipment types
- "Ground" finds all ground-based types
- "Vehicle" finds all vehicle types
This is useful for finding types based on their hierarchical classification. Returns an empty slice if no matches are found.
Example ¶
package main
import (
"fmt"
"sort"
"github.com/NERVsystems/cotlib"
)
func main() {
types := cotlib.FindTypesByFullName("Gnd/Equip/Nbc Equipment")
// Sort by name for consistent output
sort.Slice(types, func(i, j int) bool {
return types[i].Name < types[j].Name
})
for _, t := range types {
fmt.Printf("Found type: %s (%s)\n", t.Name, t.FullName)
}
}
Output: Found type: a-f-G-E-X-N (Gnd/Equip/Nbc Equipment) Found type: a-h-G-E-X-N (Gnd/Equip/Nbc Equipment) Found type: a-n-G-E-X-N (Gnd/Equip/Nbc Equipment) Found type: a-u-G-E-X-N (Gnd/Equip/Nbc Equipment)
func GetTypeDescription ¶
GetTypeDescription returns the human-readable description for a CoT type. For example, "a-f-G-E-X-N" returns "NBC EQUIPMENT".
The description is a concise explanation of what the type represents, suitable for display in user interfaces and logs.
Returns an error if the type is not registered in the catalog.
Example ¶
package main
import (
"fmt"
"github.com/NERVsystems/cotlib"
)
func main() {
desc, err := cotlib.GetTypeDescription("a-f-G-E-X-N")
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Description: %s\n", desc)
}
Output: Description: NBC EQUIPMENT
func GetTypeFullName ¶
GetTypeFullName returns the full hierarchical name for a CoT type. For example, "a-f-G-E-X-N" returns "Gnd/Equip/Nbc Equipment".
The full name represents the type's position in the CoT type hierarchy, making it useful for building user interfaces and documentation.
Returns an error if the type is not registered in the catalog.
Example ¶
package main
import (
"fmt"
"github.com/NERVsystems/cotlib"
)
func main() {
fullName, err := cotlib.GetTypeFullName("a-f-G-E-X-N")
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Full name: %s\n", fullName)
}
Output: Full name: Gnd/Equip/Nbc Equipment
func LoadCoTTypesFromFile ¶
LoadCoTTypesFromFile loads CoT types from a file
func LookupType ¶
LookupType returns the Type for the given name if it exists
func RegisterAllCoTTypes ¶
func RegisterAllCoTTypes() error
RegisterAllCoTTypes is a no-op since XML is already embedded
func RegisterCoTType ¶
func RegisterCoTType(name string)
RegisterCoTType adds a specific CoT type to the valid types registry It does not log individual type registrations to avoid log spam
func RegisterCoTTypesFromFile ¶
RegisterCoTTypesFromFile loads and registers CoT types from an XML file
func RegisterCoTTypesFromReader ¶
RegisterCoTTypesFromReader loads and registers CoT types from an XML reader
func RegisterCoTTypesFromXMLContent ¶
RegisterCoTTypesFromXMLContent registers CoT types from the given XML content string This is particularly useful for embedding the CoTtypes.xml content directly in code
func ReleaseEvent ¶ added in v0.2.6
func ReleaseEvent(e *Event)
func SetMaxValueLen ¶
func SetMaxValueLen(max int64)
SetMaxValueLen sets the maximum allowed length for XML attribute values and character data This is used to prevent memory exhaustion attacks via large XML payloads
func ValidateLatLon ¶
ValidateLatLon checks if latitude and longitude are within valid ranges
func ValidateType ¶
ValidateType checks if a CoT type is valid
Example ¶
package main
import (
"fmt"
"github.com/NERVsystems/cotlib"
)
func main() {
// Test various CoT types
types := []string{
"a-f-G", // Friendly ground
"a-h-A", // Hostile air
"b-d", // Detection
"t-x-takp-v", // TAK presence
"invalid", // Invalid type
}
for _, typ := range types {
err := cotlib.ValidateType(typ)
fmt.Printf("Type %s: %v\n", typ, err == nil)
}
}
Output: Type a-f-G: true Type a-h-A: true Type b-d: true Type t-x-takp-v: true Type invalid: false
Types ¶
type CoTTime ¶
CoTTime represents a time in CoT format (UTC without timezone offset)
func (CoTTime) MarshalXML ¶
MarshalXML implements xml.Marshaler
func (CoTTime) MarshalXMLAttr ¶
MarshalXMLAttr implements xml.MarshalerAttr
func (*CoTTime) UnmarshalXML ¶
UnmarshalXML implements xml.Unmarshaler
type Contact ¶
type Contact struct {
Callsign string `xml:"callsign,attr,omitempty"`
}
Contact represents contact information
type Detail ¶
type Detail struct {
Group *Group `xml:"group,omitempty"`
Contact *Contact `xml:"contact,omitempty"`
}
Detail contains additional information about an event
type Event ¶
type Event struct {
XMLName xml.Name `xml:"event"`
Version string `xml:"version,attr"`
Uid string `xml:"uid,attr"`
Type string `xml:"type,attr"`
How string `xml:"how,attr,omitempty"`
Time CoTTime `xml:"time,attr"`
Start CoTTime `xml:"start,attr"`
Stale CoTTime `xml:"stale,attr"`
Point Point `xml:"point"`
Detail *Detail `xml:"detail,omitempty"`
Links []Link `xml:"link,omitempty"`
}
Event represents a CoT event message
func NewEvent ¶
NewEvent creates a new CoT event with the given parameters
Example ¶
package main
import (
"fmt"
"github.com/NERVsystems/cotlib"
)
func main() {
// Create a new event with a friendly ground unit
event, err := cotlib.NewEvent("test123", "a-f-G", 30.0, -85.0, 0.0)
if err != nil {
fmt.Printf("Error creating event: %v\n", err)
return
}
// Add some details
event.Detail = &cotlib.Detail{
Contact: &cotlib.Contact{
Callsign: "TEST-1",
},
}
// Print event details
fmt.Printf("Event Type: %s\n", event.Type)
fmt.Printf("Location: %.2f, %.2f\n", event.Point.Lat, event.Point.Lon)
fmt.Printf("Callsign: %s\n", event.Detail.Contact.Callsign)
}
Output: Event Type: a-f-G Location: 30.00, -85.00 Callsign: TEST-1
func NewPresenceEvent ¶
NewPresenceEvent creates a new presence event (t-x-takp-v)
func UnmarshalXMLEvent ¶
UnmarshalXMLEvent parses an XML byte slice into an Event
func (*Event) AddLink ¶
AddLink adds a link to the event
Example ¶
package main
import (
"fmt"
"github.com/NERVsystems/cotlib"
)
func main() {
// Create a main event
event, err := cotlib.NewEvent("test123", "a-f-G", 30.0, -85.0, 0.0)
if err != nil {
fmt.Printf("Error creating event: %v\n", err)
return
}
// Add a link to another unit
event.AddLink(&cotlib.Link{
Uid: "TARGET1",
Type: "a-f-G",
Relation: "wingman",
})
// Print link details
for _, link := range event.Links {
fmt.Printf("Linked to: %s\n", link.Uid)
fmt.Printf("Link type: %s\n", link.Type)
fmt.Printf("Relation: %s\n", link.Relation)
}
}
Output: Linked to: TARGET1 Link type: a-f-G Relation: wingman
func (*Event) InjectIdentity ¶
InjectIdentity adds identity information to the event
Example ¶
package main
import (
"fmt"
"github.com/NERVsystems/cotlib"
)
func main() {
// Create a new event
event, err := cotlib.NewEvent("test123", "a-f-G", 30.0, -85.0, 0.0)
if err != nil {
fmt.Printf("Error creating event: %v\n", err)
return
}
// Inject identity information
event.InjectIdentity("self123", "Blue", "HQ")
// Print identity details
if event.Detail != nil && event.Detail.Group != nil {
fmt.Printf("Group: %s\n", event.Detail.Group.Name)
fmt.Printf("Role: %s\n", event.Detail.Group.Role)
}
}
Output: Group: Blue Role: HQ
func (*Event) Is ¶
Is checks if the event matches a predicate
Example ¶
package main
import (
"fmt"
"github.com/NERVsystems/cotlib"
)
func main() {
// Create a friendly ground unit event
event, err := cotlib.NewEvent("test123", "a-f-G", 30.0, -85.0, 0.0)
if err != nil {
fmt.Printf("Error creating event: %v\n", err)
return
}
// Check various predicates
fmt.Printf("Is friendly: %v\n", event.Is("friend"))
fmt.Printf("Is hostile: %v\n", event.Is("hostile"))
fmt.Printf("Is ground: %v\n", event.Is("ground"))
fmt.Printf("Is air: %v\n", event.Is("air"))
}
Output: Is friendly: true Is hostile: false Is ground: true Is air: false
type Link ¶
type Link struct {
Uid string `xml:"uid,attr"`
Type string `xml:"type,attr"`
Relation string `xml:"relation,attr"`
}
Link represents a relationship to another event
type Point ¶
type Point struct {
Lat float64 `xml:"lat,attr"` // Latitude in degrees
Lon float64 `xml:"lon,attr"` // Longitude in degrees
Hae float64 `xml:"hae,attr"` // Height above ellipsoid in meters
Ce float64 `xml:"ce,attr"` // Circular error in meters
Le float64 `xml:"le,attr"` // Linear error in meters
}
Point represents a location in 3D space with error estimates