diff --git a/cmd/goatak_server/main.go b/cmd/goatak_server/main.go index 09567e4..b269b09 100644 --- a/cmd/goatak_server/main.go +++ b/cmd/goatak_server/main.go @@ -394,7 +394,7 @@ func (app *App) SendToCallsign(callsign string, msg *cot.CotMessage) { func (app *App) SendToUid(uid string, msg *cot.CotMessage) { app.ForAllClients(func(ch client.ClientHandler) bool { - if ch.HasUid(uid) { + if ch.HasUID(uid) { if err := ch.SendMsg(msg); err != nil { app.Logger.Errorf("error: %v", err) } diff --git a/cmd/goatak_server/metrics.go b/cmd/goatak_server/metrics.go index 2480d68..cc30967 100644 --- a/cmd/goatak_server/metrics.go +++ b/cmd/goatak_server/metrics.go @@ -1,3 +1,4 @@ +//nolint:gochecknoglobals package main import ( diff --git a/cmd/goatak_server/templates/map.html b/cmd/goatak_server/templates/map.html index 8f1afbe..5b551b4 100644 --- a/cmd/goatak_server/templates/map.html +++ b/cmd/goatak_server/templates/map.html @@ -14,8 +14,8 @@
  • - * {{u.callsign}} ({{u.status}}) + * {{ u.callsign }} ({{ u.status }})
  • @@ -23,12 +23,12 @@ @@ -61,14 +61,14 @@
    -
    Me ({{config.callsign}})
    +
    Me ({{ config.callsign }})
    - UID: {{config.uid}}
    + UID: {{ config.uid }}
    - Team: {{config.team}}, Role:{{config.role}} + Team: {{ config.team }}, Role:{{ config.role }}
    - coords: {{printCoords(config.lat, config.lon)}} + coords: {{ printCoords(config.lat, config.lon) }} @@ -88,21 +88,21 @@
    - RedX: {{printCoordsll(getTool('redx').getLatLng())}} + RedX: {{ printCoordsll(getTool('redx').getLatLng()) }} X
    - DP1: {{printCoordsll(getTool('dp1').getLatLng())}} + DP1: {{ printCoordsll(getTool('dp1').getLatLng()) }} X
    - cursor: {{printCoordsll(coords)}} cursor: {{ printCoordsll(coords) }} ({{ distBea(getTool('redx').getLatLng(), coords) }} from RedX)
    @@ -111,8 +111,8 @@
    - {{getUnitName(current_unit)}} ({{current_unit.status}}) + {{ getUnitName(current_unit) }} ({{ current_unit.status }}) @@ -131,13 +131,13 @@
    - UID: {{current_unit.uid}}
    + UID: {{ current_unit.uid }}
    - Team: {{current_unit.team}}, - Role: {{current_unit.role}} + Team: {{ current_unit.team }}, + Role: {{ current_unit.role }}
    - Type: {{current_unit.type}} SIDC: {{current_unit.sidc}} + Type: {{ current_unit.type }} SIDC: {{ current_unit.sidc }}
    coords: {{ printCoords(current_unit.lat, current_unit.lon) }} diff --git a/cmd/goatak_server/ws.go b/cmd/goatak_server/ws.go index 4685508..24616d3 100644 --- a/cmd/goatak_server/ws.go +++ b/cmd/goatak_server/ws.go @@ -48,7 +48,7 @@ func (w *WsClientHandler) GetUids() map[string]string { return res } -func (w *WsClientHandler) HasUid(uid string) bool { +func (w *WsClientHandler) HasUID(uid string) bool { _, ok := w.uids.Load(uid) return ok } diff --git a/cmd/webclient/enroll.go b/cmd/webclient/enroll.go index e439c55..dbb3c58 100644 --- a/cmd/webclient/enroll.go +++ b/cmd/webclient/enroll.go @@ -28,7 +28,7 @@ type Enroller struct { logger *zap.SugaredLogger host string port int - cl *http.Client + client *http.Client user string passwd string save bool @@ -55,38 +55,61 @@ func NewEnroller(logger *zap.SugaredLogger, host, user, passwd string, save bool passwd: passwd, port: 8446, save: save, - cl: &http.Client{Timeout: time.Second * 30, Transport: &http.Transport{TLSClientConfig: tlsConf}}, + client: &http.Client{Timeout: time.Second * 30, Transport: &http.Transport{TLSClientConfig: tlsConf}}, } } -func (e *Enroller) baseUrl() string { - return fmt.Sprintf("https://%s:%d", e.host, e.port) +func (e *Enroller) getUrl(path string) string { + return fmt.Sprintf("https://%s:%d%s", e.host, e.port, path) } -func (e *Enroller) getConfig() (*CertificateConfig, error) { - e.logger.Infof("getting tls config") - req, err := http.NewRequest(http.MethodGet, e.baseUrl()+"/Marti/api/tls/config", http.NoBody) +func (e *Enroller) request(method, path string, args map[string]string, body io.Reader) (io.ReadCloser, error) { + url := e.getUrl(path) + req, err := http.NewRequest(method, url, body) if err != nil { return nil, err } - req.Header.Del("User-Agent") + req.SetBasicAuth(e.user, e.passwd) - res, err := e.cl.Do(req) + req.Header.Del("User-Agent") + + if args != nil && len(args) > 0 { + q := req.URL.Query() + + for k, v := range args { + q.Add(k, v) + + } + req.URL.RawQuery = q.Encode() + } + + res, err := e.client.Do(req) if err != nil { return nil, err } if res.StatusCode != http.StatusOK { - return nil, fmt.Errorf("bad status: %d", res.StatusCode) + return nil, fmt.Errorf("status is %s", res.Status) } if res.Body == nil { - return nil, nil + return nil, fmt.Errorf("null body") } - defer res.Body.Close() + return res.Body, nil +} - dec := xml.NewDecoder(res.Body) +func (e *Enroller) getConfig() (*CertificateConfig, error) { + e.logger.Infof("getting tls config") + body, err := e.request(http.MethodGet, "/Marti/api/tls/config", nil, nil) + + if err != nil { + return nil, err + } + + defer body.Close() + + dec := xml.NewDecoder(body) conf := new(CertificateConfig) err = dec.Decode(conf) @@ -97,6 +120,7 @@ func (e *Enroller) getOrEnrollCert(uid, version string) (*tls.Certificate, []*x5 fname := fmt.Sprintf("%s_%s.p12", e.host, e.user) if cert, cas, err := loadP12(fname, viper.GetString("ssl.password")); err == nil { e.logger.Infof("loading cert from file %s", fname) + return cert, cas, nil } @@ -121,45 +145,27 @@ func (e *Enroller) getOrEnrollCert(uid, version string) (*tls.Certificate, []*x5 } csr, key := makeCsr(subj) + e.logger.Infof("signing cert on server") - req, err := http.NewRequest(http.MethodPost, e.baseUrl()+"/Marti/api/tls/signClient/v2", strings.NewReader(csr)) - if err != nil { - return nil, nil, err - } - q := req.URL.Query() - q.Add("clientUID", uid) - q.Add("version", version) - req.URL.RawQuery = q.Encode() + args := map[string]string{"clientUID": uid, "version": version} + body, err := e.request(http.MethodPost, "/Marti/api/tls/signClient/v2", args, strings.NewReader(csr)) - req.Header.Set("Accept", "application/json") - req.Header.Set("Content-Type", "application/octet-stream") - req.Header.Del("User-Agent") - req.SetBasicAuth(e.user, e.passwd) - res, err := e.cl.Do(req) if err != nil { return nil, nil, err } - if res.StatusCode != http.StatusOK { - return nil, nil, fmt.Errorf("bad status: %d", res.StatusCode) - } + defer body.Close() var certs map[string]string - if err := json.NewDecoder(res.Body).Decode(&certs); err != nil { + if err := json.NewDecoder(body).Decode(&certs); err != nil { return nil, nil, err } - if res.Body == nil { - return nil, nil, fmt.Errorf("empty response") - } - var cert *x509.Certificate ca := make([]*x509.Certificate, 0) - defer res.Body.Close() - for name, c := range certs { crt, err := tlsutil.ParseCert(c) if err != nil { @@ -199,38 +205,23 @@ func (e *Enroller) getOrEnrollCert(uid, version string) (*tls.Certificate, []*x5 } func (e *Enroller) getProfile(uid string) error { - req, err := http.NewRequest(http.MethodGet, e.baseUrl()+"/Marti/api/tls/profile/enrollment", nil) - if err != nil { - return err - } + args := map[string]string{"clientUID": uid} + body, err := e.request(http.MethodGet, "/Marti/api/tls/profile/enrollment", args, nil) - q := req.URL.Query() - q.Add("clientUID", uid) - req.URL.RawQuery = q.Encode() - req.Header.Del("User-Agent") - req.SetBasicAuth(e.user, e.passwd) - res, err := e.cl.Do(req) if err != nil { return err } - if res.StatusCode != http.StatusOK { - return fmt.Errorf("bad status: %d", res.StatusCode) - } - - if res.Body == nil { - return fmt.Errorf("null body") - } - - defer res.Body.Close() + defer body.Close() f, err := os.Create(e.host + ".zip") if err != nil { return err } - _, err = io.Copy(f, res.Body) - f.Close() + defer f.Close() + + _, err = io.Copy(f, body) return err } @@ -244,7 +235,7 @@ func makeCsr(subj *pkix.Name) (string, *rsa.PrivateKey) { csrBytes, _ := x509.CreateCertificateRequest(rand.Reader, &template, keyBytes) - csr := string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE REQUEST", Bytes: csrBytes})) + csr := string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE REQUEST", Bytes: csrBytes, Headers: nil})) csr = strings.ReplaceAll(csr, "-----BEGIN CERTIFICATE REQUEST-----\n", "") csr = strings.ReplaceAll(csr, "\n-----END CERTIFICATE REQUEST-----", "") diff --git a/cmd/webclient/main.go b/cmd/webclient/main.go index 122848f..06888c2 100644 --- a/cmd/webclient/main.go +++ b/cmd/webclient/main.go @@ -132,7 +132,7 @@ func (app *App) Init(cancel context.CancelFunc) { app.remoteApi = NewRemoteApi(app.host) if app.tls { - app.remoteApi.SetTls(app.getTlsConfig()) + app.remoteApi.SetTls(app.getTLSConfig()) } app.ch = make(chan []byte, 20) diff --git a/cmd/webclient/tcp_handler.go b/cmd/webclient/tcp_handler.go index 6a2da23..0e39488 100644 --- a/cmd/webclient/tcp_handler.go +++ b/cmd/webclient/tcp_handler.go @@ -13,7 +13,7 @@ func (app *App) connect() (net.Conn, error) { addr := fmt.Sprintf("%s:%s", app.host, app.tcpPort) if app.tls { app.Logger.Infof("connecting with SSL to %s...", addr) - conn, err := tls.Dial("tcp", addr, app.getTlsConfig()) + conn, err := tls.Dial("tcp", addr, app.getTLSConfig()) if err != nil { return nil, err } @@ -34,8 +34,8 @@ func (app *App) connect() (net.Conn, error) { } } -func (app *App) getTlsConfig() *tls.Config { - conf := &tls.Config{ +func (app *App) getTLSConfig() *tls.Config { + conf := &tls.Config{ //nolint:exhaustruct Certificates: []tls.Certificate{*app.tlsCert}, RootCAs: app.cas, ClientCAs: app.cas, diff --git a/cmd/webclient/ui.go b/cmd/webclient/ui.go index f20e6ba..3af413f 100644 --- a/cmd/webclient/ui.go +++ b/cmd/webclient/ui.go @@ -18,6 +18,7 @@ func (app *App) layout(g *gocui.Gui) error { if !errors.Is(err, gocui.ErrUnknownView) { return err } + v.Frame = true } @@ -25,6 +26,7 @@ func (app *App) layout(g *gocui.Gui) error { if !errors.Is(err, gocui.ErrUnknownView) { return err } + v.Frame = true v.Title = "Log" } diff --git a/data/defaults.pref b/data/defaults.pref index 66bce61..157e4e0 100644 --- a/data/defaults.pref +++ b/data/defaults.pref @@ -1,15 +1,15 @@ - - 1 - 1 - false - MSL - DM - 1 - 0 - 1 - true - true - + + 1 + 1 + false + MSL + DM + 1 + 0 + 1 + true + true + \ No newline at end of file diff --git a/doc/CoTtypes.xml b/doc/CoTtypes.xml index bb468c6..12b11f7 100644 --- a/doc/CoTtypes.xml +++ b/doc/CoTtypes.xml @@ -37,2285 +37,2418 @@ --> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/event.xsd b/doc/event.xsd index c8839c7..8d6a250 100644 --- a/doc/event.xsd +++ b/doc/event.xsd @@ -44,11 +44,11 @@ MITRE Case #11-3895 (Event-PUBLIC.xsd) The first component (component1) is a hierarchically organized hint about type. The intention is that this hierarchy be flexible and extensible and - facilitate simple filtering, translation and display. To - facilitate filtering, the hierarchy needs to present key - fields in an easily parsed and logical order. To facilitate + facilitate simple filtering, translation and display. To + facilitate filtering, the hierarchy needs to present key + fields in an easily parsed and logical order. To facilitate this, this component is a composite of fields separated by the "-" punctuation - character, so a valid type would be: x-x-X-X-x. Using a + character, so a valid type would be: x-x-X-X-x. Using a punctuation for field separation allows arbitrary expansion of the type space, e.g., a-fzp-mlk-gm-... @@ -76,34 +76,34 @@ MITRE Case #11-3895 (Event-PUBLIC.xsd) format - digit-character-character as defined below The QoS attribute will determine the preferential treatment events - receive as they proceed through the kill chain. The field has + receive as they proceed through the kill chain. The field has several distinct but related components. A "priority" value indicates queuing and processing order for - competing events. At a processing bottleneck (e.g., bandwidth + competing events. At a processing bottleneck (e.g., bandwidth limited link) high priority events will be processed before lower - priority events. Priority determines queuing order at a + priority events. Priority determines queuing order at a bottleneck. 9 - highest (most significant) priority 0 - lowest (least significant) priority A "overtaking" value indicates how two events for the same uid are - reconciled when they "catch up" to one another. The more recent + reconciled when they "catch up" to one another. The more recent event (by timestamp) may supersede the older event (deleting the old event) when it catches it, or it may follow the old event so that event order is preserved, or it may be routed independently of previous events. r - replace - new event replaces (deletes) old event - f - follow - new event must follow previous events + f - follow - new event must follow previous events i - independent - new event processed independently of old events An "assurance" value indicates how much effort must be placed in - delivering this particular event. Events from sources that + delivering this particular event. Events from sources that continually send updates (blue force tracks) or that are sent for information purposes only require a lower level of delivery - effort. Events that are singletons (sent only once) and are + effort. Events that are singletons (sent only once) and are critical require guaranteed delivery. g - guaranteed delivery (message never dropped even if delivered late) @@ -115,16 +115,16 @@ MITRE Case #11-3895 (Event-PUBLIC.xsd) qos="1-r-c" Note that different events with the same UID may have differing - QoS values. This enables a graceful degradation in the presence - of congestion. For example, a blue force tracker may output a + QoS values. This enables a graceful degradation in the presence + of congestion. For example, a blue force tracker may output a sequence of events with like - ... qos="1-r-c" ... frequent, low priority updates + ... qos="1-r-c" ... frequent, low priority updates ... qos="1-r-c" ... ... qos="1-r-c" ... - ... qos="5-r-d" ... occasional "push" priority update + ... qos="5-r-d" ... occasional "push" priority update ... qos="1-r-c" ... ... qos="1-r-c" ... - ... qos="9-r-g" ... "Mayday" position report + ... qos="9-r-g" ... "Mayday" position report @@ -138,12 +138,12 @@ MITRE Case #11-3895 (Event-PUBLIC.xsd) The opex field is intended to indicate that the event is part of a - live operation, an exercise, or a simulation. For backward compatibility, absence + live operation, an exercise, or a simulation. For backward compatibility, absence of the opex indicates "no statement", which will be interpreted in an installation specific manner. - opex="o-<name>" or "e-<nickname>" or "s-<nickname>", - where "-<name>" is optional. That is, it is permissible to + opex="o-<name>" or "e-<nickname>" or "s-<nickname>", + where "-<name>" is optional. That is, it is permissible to specify only "o", "e", or "s" for the opex value. o = operations @@ -156,7 +156,8 @@ MITRE Case #11-3895 (Event-PUBLIC.xsd) The "uid" attribute is a globally unique name for this specific piece of information. - Several "events" may be associated with one UID, but in that case, the latest (ordered by timestamp), + Several "events" may be associated with one UID, but in that case, the latest (ordered by + timestamp), overwrites all previous events for that UID. @@ -165,12 +166,12 @@ MITRE Case #11-3895 (Event-PUBLIC.xsd) The CoT XML schema includes three time values: - time, start, and stale. "time" is a time stamp placed on the event + time, start, and stale. "time" is a time stamp placed on the event when generated. start and stale define an interval in time for which the event is valid. Example: For the scenario where we have intel reports about a meeting of terrorist operatives later in the day: An event might be generated at noon (time) to describe a ground based - target which is valid from 1300 (start) until 1330 (stale). All time + target which is valid from 1300 (start) until 1330 (stale). All time fields are required. In version 1.1 of the CoT schema, the time and stale attributes together defined and interval of time for which the event was valid. In V2.0, time indicates the "birth" of an event and the start and stale pair @@ -179,9 +180,9 @@ MITRE Case #11-3895 (Event-PUBLIC.xsd) The "time" attribute is a time stamp indicating when an event was generated. The format of time, start, and stale are in standard date format (ISO 8601): CCYY-MM-DDThh:mm:ss.ssZ (e.g., 2002-10-05T17:01:14.00Z), where the presence of - fractional seconds (including the delimeter) is optional. Also, there is no constraint - on the number of digits to use for fractional seconds. The following are all valid: - 2002-10-05T18:00:23Z, 2002-10-05T18:00:23.12Z, 2002-10-05T18:00:23.123456Z + fractional seconds (including the delimeter) is optional. Also, there is no constraint + on the number of digits to use for fractional seconds. The following are all valid: + 2002-10-05T18:00:23Z, 2002-10-05T18:00:23.12Z, 2002-10-05T18:00:23.123456Z @@ -211,11 +212,11 @@ MITRE Case #11-3895 (Event-PUBLIC.xsd) format = character-character The "how" attribute gives a hint about how the coordinates were - generated. It is used specifically to relay a hint about the + generated. It is used specifically to relay a hint about the types of errors that may be expected in the data and to weight the - data in systems that fuse multiple inputs. For example, + data in systems that fuse multiple inputs. For example, coordinates transcribed by humans may have digit transposition, - missing or repeated digits, estimated error bounds, etc. As such, + missing or repeated digits, estimated error bounds, etc. As such, they may require special attention as they propagate through the kill chain (e.g., they may require an additional review). Similarly, machine generated coordinates derived solely from @@ -230,15 +231,15 @@ MITRE Case #11-3895 (Event-PUBLIC.xsd) m - machine generated i - mensurated (from imagery) g - derived from GPS receiver - m - magnetic - derived from magnetic sources - s - simulated - out of a simulation - f - fused - corroborated from multiple sources - c - configured - out of a configuration file - p - predicted - prediction of future (e.g., a from a tracker) - r - relayed - imported from another system (gateway) + m - magnetic - derived from magnetic sources + s - simulated - out of a simulation + f - fused - corroborated from multiple sources + c - configured - out of a configuration file + p - predicted - prediction of future (e.g., a from a tracker) + r - relayed - imported from another system (gateway) As with other compound fields, the elements of the how field - will be delimited by the field separator character "-". E.g, + will be delimited by the field separator character "-". E.g, A coordinate mensurated from imagery would have a how field of "m-i". @@ -259,18 +260,18 @@ MITRE Case #11-3895 (Event-PUBLIC.xsd) The "detail" entity is intended to carry information that is specific to smaller communities of producers and consumers and - require more intimate knowledge of the operating domain. For + require more intimate knowledge of the operating domain. For example, mensurated "target" events may come from dramatically different sources and need to propagate dramatically different - "detail" information. A close-air-support mission will augment + "detail" information. A close-air-support mission will augment target details with initial point and callsign details to - facilitate coordination of weapon delivery. In contrast, a + facilitate coordination of weapon delivery. In contrast, a mission planning system may augment planned targets with target catalog information and weapon fuzing requirements. Because the "details" portion of the event are of interest only to a subset of subscribers, that entity may be mentioned by reference - when the event is communicated. This reduces the congestion when + when the event is communicated. This reduces the congestion when events are transmitted over bandwidth limited links and also prevents the retransmission of static data elements. @@ -286,7 +287,9 @@ MITRE Case #11-3895 (Event-PUBLIC.xsd) - Latitude based on WGS-84 ellipsoid in signed degree-decimal format (e.g. -33.350000). Range -90 -> +90. + Latitude based on WGS-84 ellipsoid in signed degree-decimal format (e.g. + -33.350000). Range -90 -> +90. + @@ -297,7 +300,9 @@ MITRE Case #11-3895 (Event-PUBLIC.xsd) - Longitude based on WGS-84 ellipsoid in signed degree-decimal format (e.g. 44.383333). Range -180 -> +180. + Longitude based on WGS-84 ellipsoid in signed degree-decimal format (e.g. + 44.383333). Range -180 -> +180. + @@ -308,7 +313,9 @@ MITRE Case #11-3895 (Event-PUBLIC.xsd) - HAE acronym for Height above Ellipsoid based on WGS-84 ellipsoid (measured in meters). + HAE acronym for Height above Ellipsoid based on WGS-84 ellipsoid (measured in + meters). + @@ -317,7 +324,7 @@ MITRE Case #11-3895 (Event-PUBLIC.xsd) Circular Error around point defined by lat and lon fields in meters. Although named ce, this field is intended to define a circular area around the event point, not necessarily an error (e.g. Describing a reservation area is not an - "error"). If it is appropriate for the "ce" field to represent + "error"). If it is appropriate for the "ce" field to represent an error value (e.g. event describes laser designated target), the value will represent the one sigma point for a zero mean normal (Guassian) distribution. diff --git a/internal/client/client_handler.go b/internal/client/client_handler.go index 4015c52..f741e1c 100644 --- a/internal/client/client_handler.go +++ b/internal/client/client_handler.go @@ -36,7 +36,7 @@ type HandlerConfig struct { type ClientHandler interface { GetName() string - HasUid(uid string) bool + HasUID(uid string) bool GetUids() map[string]string GetUser() *model.User GetVersion() int32 @@ -117,8 +117,9 @@ func (h *ConnClientHandler) GetUids() map[string]string { return res } -func (h *ConnClientHandler) HasUid(uid string) bool { +func (h *ConnClientHandler) HasUID(uid string) bool { _, ok := h.uids.Load(uid) + return ok } @@ -207,6 +208,7 @@ func (h *ConnClientHandler) handleRead() { if msg.IsContact() { uid := msg.GetUid() uid = strings.TrimSuffix(uid, "-ping") + if _, present := h.uids.Swap(uid, msg.GetCallsign()); !present { if h.newContactCb != nil { h.newContactCb(uid, msg.GetCallsign()) @@ -224,6 +226,7 @@ func (h *ConnClientHandler) handleRead() { // ping if msg.GetType() == "t-x-c-t" { h.logger.Debugf("ping from %s %s", h.addr, msg.GetUid()) + if err := h.SendCot(cot.MakePong()); err != nil { h.logger.Errorf("SendMsg error: %v", err) } @@ -270,9 +273,9 @@ func (h *ConnClientHandler) processXMLRead(er *cot.TagReader) (*cot.CotMessage, h.SetVersion(1) return nil, nil - } else { - return nil, fmt.Errorf("error on send ok: %w", err) } + + return nil, fmt.Errorf("error on send ok: %w", err) } } diff --git a/pkg/cot/node.go b/pkg/cot/node.go index 72159e5..59f2a55 100644 --- a/pkg/cot/node.go +++ b/pkg/cot/node.go @@ -7,6 +7,7 @@ import ( "strings" ) +//nolint:musttag type Node struct { XMLName xml.Name Attrs []xml.Attr `xml:",any,attr"` diff --git a/pkg/cot/tagreader.go b/pkg/cot/tagreader.go index 3d56c43..5f73835 100644 --- a/pkg/cot/tagreader.go +++ b/pkg/cot/tagreader.go @@ -8,6 +8,8 @@ import ( "strings" ) +const maxBufLen = 2048 + type TagReader struct { r io.ByteReader } @@ -44,13 +46,16 @@ func (er *TagReader) ReadTag() (string, []byte, error) { return "", nil, err } buf.WriteByte(b) + if b == '>' { break } + if b == '<' { return "", nil, fmt.Errorf("bad xml: %s", buf.String()) } - if buf.Len() > 2048 { + + if buf.Len() > maxBufLen { return "", nil, fmt.Errorf("too long tag") } } @@ -102,7 +107,8 @@ func (er *TagReader) ReadTag() (string, []byte, error) { } buf.Reset() } - if saved.Len() > 2048 { + + if saved.Len() > maxBufLen { return "", nil, fmt.Errorf("too long tag") } } diff --git a/pkg/cot/types.go b/pkg/cot/types.go index c5a88e6..2e19647 100644 --- a/pkg/cot/types.go +++ b/pkg/cot/types.go @@ -53,6 +53,7 @@ func init() { t1 := strings.Join(n[:i], "-") if ct1, ok := types[t1]; ok { found = true + ct1.Next = append(ct1.Next, ct) break diff --git a/pkg/model/chat_test.go b/pkg/model/chat_test.go index 47bdecf..a67faba 100644 --- a/pkg/model/chat_test.go +++ b/pkg/model/chat_test.go @@ -20,9 +20,9 @@ func getChatMsg(msgID, uidFrom, userFrom, uidTo, userTo, text string) *cot.CotMe m := cot.BasicMsg("b-t-f", fmt.Sprintf("GeoChat.%s.%s.%s", uidFrom, uidTo, msgID), time.Minute) xd, _ := cot.DetailsFromString(d) - m.CotEvent.Detail = &cotproto.Detail{XmlDetail: xd.AsXMLString()} + m.CotEvent.Detail = &cotproto.Detail{XmlDetail: xd.AsXMLString()} //nolint:exhaustruct - return &cot.CotMessage{TakMessage: m, Detail: xd} + return &cot.CotMessage{TakMessage: m, Detail: xd, From: "", Scope: ""} } func TestChatFromMe(t *testing.T) { @@ -73,7 +73,7 @@ func TestBtfd(t *testing.T) { m := cot.BasicMsg("b-t-f-d", "4de0262c-633f-46eb-b8e5-5ef1eb1e5e22", time.Minute) xd, _ := cot.DetailsFromString(d) m.CotEvent.Detail = &cotproto.Detail{XmlDetail: xd.AsXMLString()} - msg := cot.CotMessage{TakMessage: m, Detail: xd} + msg := cot.CotMessage{TakMessage: m, Detail: xd, From: "", Scope: ""} assert.True(t, msg.IsChatReceipt()) } @@ -88,7 +88,7 @@ func TestBtfr(t *testing.T) { m := cot.BasicMsg("b-t-f-r", "4de0262c-633f-46eb-b8e5-5ef1eb1e5e22", time.Minute) xd, _ := cot.DetailsFromString(d) m.CotEvent.Detail = &cotproto.Detail{XmlDetail: xd.AsXMLString()} - msg := cot.CotMessage{TakMessage: m, Detail: xd} + msg := cot.CotMessage{TakMessage: m, Detail: xd, From: "", Scope: ""} assert.True(t, msg.IsChatReceipt()) } @@ -105,7 +105,7 @@ func TestMsgRed(t *testing.T) { m := cot.BasicMsg("b-t-f", "GeoChat.uid1.Red.9f46716f-c875-43b0-8162-3da74196353f", time.Minute) xd, _ := cot.DetailsFromString(d) m.CotEvent.Detail = &cotproto.Detail{XmlDetail: xd.AsXMLString()} - msg := cot.CotMessage{TakMessage: m, Detail: xd} + msg := cot.CotMessage{TakMessage: m, Detail: xd, From: "", Scope: ""} assert.True(t, msg.IsChat()) diff --git a/pkg/model/http.go b/pkg/model/http.go index 9ebd876..b05d21c 100644 --- a/pkg/model/http.go +++ b/pkg/model/http.go @@ -81,7 +81,7 @@ func (i *Item) ToWeb() *WebUnit { Sidc: getSIDC(i.cottype), ParentUID: i.parentUID, ParentCallsign: i.parentCallsign, - Color: fmt.Sprintf("#%.6x", i.color&0xffffff), + Color: i.color, Icon: i.icon, Local: i.local, Send: i.send, diff --git a/pkg/model/icons_test.go b/pkg/model/icons_test.go index 04b12ae..e451e03 100644 --- a/pkg/model/icons_test.go +++ b/pkg/model/icons_test.go @@ -13,6 +13,7 @@ func TestSiDC(t *testing.T) { func checkSIDC(t *testing.T, fn, sidc string) { t.Helper() + if getSIDC(fn) != sidc { t.Errorf("got %s, must be %s", getSIDC(fn), sidc) } diff --git a/pkg/model/unit.go b/pkg/model/unit.go index bcee98a..ce75a61 100644 --- a/pkg/model/unit.go +++ b/pkg/model/unit.go @@ -2,7 +2,6 @@ package model import ( "fmt" - "strconv" "strings" "sync" "time" @@ -33,7 +32,7 @@ type Item struct { send bool parentCallsign string parentUID string - color uint32 + color string icon string track []*Pos msg *cot.CotMessage @@ -145,6 +144,7 @@ func GetClass(msg *cot.CotMessage) string { if msg == nil { return "" } + t := msg.GetType() switch { @@ -168,30 +168,29 @@ func FromMsg(msg *cot.CotMessage) *Item { return nil } - i := &Item{ - class: cls, - uid: msg.GetUid(), - cottype: msg.GetType(), - callsign: msg.GetCallsign(), - staleTime: msg.GetStaleTime(), - startTime: msg.GetStartTime(), - sendTime: msg.GetSendTime(), - msg: msg, - lastSeen: time.Now(), - online: true, - mx: sync.RWMutex{}, - } - - i.parentUID, i.parentCallsign = msg.GetParent() + parent, parentCs := msg.GetParent() - if c := msg.Detail.GetFirst("color"); c != nil { - if col, err := strconv.Atoi(c.GetAttr("argb")); err == nil { - i.color = uint32(col) - } + i := &Item{ + mx: sync.RWMutex{}, + uid: msg.GetUid(), + cottype: msg.GetType(), + class: cls, + callsign: msg.GetCallsign(), + staleTime: msg.GetStaleTime(), + startTime: msg.GetStartTime(), + sendTime: msg.GetSendTime(), + lastSeen: time.Now(), + online: true, + local: false, + send: false, + parentCallsign: parentCs, + parentUID: parent, + color: msg.Detail.GetFirst("color").GetAttr("argb"), + icon: msg.Detail.GetFirst("usericon").GetAttr("iconsetpath"), + track: nil, + msg: msg, } - i.icon = msg.Detail.GetFirst("usericon").GetAttr("iconsetpath") - if i.class == UNIT || i.class == CONTACT { if msg.GetLat() != 0 || msg.GetLon() != 0 { pos := &Pos{ @@ -213,6 +212,7 @@ func FromMsgLocal(msg *cot.CotMessage, send bool) *Item { i := FromMsg(msg) i.local = true i.send = send + return i } @@ -242,9 +242,7 @@ func (i *Item) Update(msg *cot.CotMessage) { i.parentUID, i.parentCallsign = msg.GetParent() if c := msg.Detail.GetFirst("color"); c != nil { - if col, err := strconv.Atoi(c.GetAttr("argb")); err == nil { - i.color = uint32(col) - } + i.color = c.GetAttr("argb") } i.icon = msg.Detail.GetFirst("usericon").GetAttr("iconsetpath") @@ -294,14 +292,9 @@ func (i *Item) UpdateFromWeb(w *WebUnit, m *cot.CotMessage) { i.parentUID = w.ParentUID i.parentCallsign = w.ParentCallsign i.icon = w.Icon + i.color = w.Color i.local = w.Local i.send = w.Send - if w.Color != "" { - if col, err := strconv.Atoi(w.Color); err == nil { - i.color = uint32(col) - } - } - i.msg = m } diff --git a/pkg/tlsutil/util.go b/pkg/tlsutil/util.go index 5f1f39c..31b1a1e 100644 --- a/pkg/tlsutil/util.go +++ b/pkg/tlsutil/util.go @@ -2,7 +2,6 @@ package tlsutil import ( "bytes" - "crypto/rsa" "crypto/x509" "encoding/pem" "fmt" @@ -12,22 +11,26 @@ import ( "software.sslmate.com/src/go-pkcs12" ) -func ParseCert(s string) (*x509.Certificate, error) { +const cr = 10 + +func ParseBlock(b []byte, typ string) *pem.Block { bb := bytes.Buffer{} - bb.WriteString("-----BEGIN CERTIFICATE-----\n") - bb.WriteString(s) - bb.WriteString("\n-----END CERTIFICATE-----") - csrBlock, _ := pem.Decode(bb.Bytes()) + bb.WriteString(fmt.Sprintf("-----BEGIN %s-----\n", typ)) + bb.Write(b) + bb.WriteString(fmt.Sprintf("\n-----END %s-----", typ)) + block, _ := pem.Decode(bb.Bytes()) + + return block +} + +func ParseCert(s string) (*x509.Certificate, error) { + csrBlock := ParseBlock([]byte(s), "CERTIFICATE") return x509.ParseCertificate(csrBlock.Bytes) } func ParseCsr(b []byte) (*x509.CertificateRequest, error) { - bb := bytes.Buffer{} - bb.WriteString("-----BEGIN CERTIFICATE REQUEST-----\n") - bb.Write(b) - bb.WriteString("\n-----END CERTIFICATE REQUEST-----") - csrBlock, _ := pem.Decode(bb.Bytes()) + csrBlock := ParseBlock(b, "REQUEST") return x509.ParseCertificateRequest(csrBlock.Bytes) } @@ -42,17 +45,9 @@ func MakeP12TrustStore(certs map[string]*x509.Certificate, passwd string) ([]byt return pkcs12.LegacyRC2.EncodeTrustStoreEntries(entries, passwd) } -func CertToPem(cert *x509.Certificate) []byte { - return pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}) -} - -func KeyToPem(key *rsa.PrivateKey) []byte { - return pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}) -} - -func CertToStr(cert *x509.Certificate, header bool) string { - s := string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})) - if header { +func CertToStr(cert *x509.Certificate, withHeader bool) string { + s := string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw, Headers: nil})) + if withHeader { return s } @@ -65,7 +60,7 @@ func CertToStr(cert *x509.Certificate, header bool) string { } sb.WriteString(s1) - sb.WriteByte(10) + sb.WriteByte(cr) } return sb.String() @@ -89,6 +84,7 @@ func LogCert(logger *zap.SugaredLogger, name string, cert *x509.Certificate) { return } + logger.Infof("%s sn: %x", name, cert.SerialNumber) logger.Infof("%s subject: %s", name, cert.Subject.String()) logger.Infof("%s issuer: %s", name, cert.Issuer.String()) diff --git a/protobuf/contact.proto b/protobuf/contact.proto index 131a4fc..e994036 100644 --- a/protobuf/contact.proto +++ b/protobuf/contact.proto @@ -7,7 +7,7 @@ option go_package = "github.com/kdudkov/goatak/cotproto"; // to the message format will be rejected and fall back to opaque // XML representation message Contact { - // Endpoint is optional; if missing/empty do not populate. - string endpoint = 1; // endpoint= - string callsign = 2; // callsign= + // Endpoint is optional; if missing/empty do not populate. + string endpoint = 1; // endpoint= + string callsign = 2; // callsign= } diff --git a/protobuf/cotevent.proto b/protobuf/cotevent.proto index baedcd7..8d1ae40 100644 --- a/protobuf/cotevent.proto +++ b/protobuf/cotevent.proto @@ -14,45 +14,45 @@ import "detail.proto"; // conversion to protobuf, the message will be // rejected message CotEvent { - // - - string type = 1; // - - string access = 2; // optional, but see below! - // field was optional in early - // cot implementations but now required - // in MIL-STD-6090. - // This message definition treats as - // "optional" due to legacy definition/use, - // but updated/new clients should be - // populating on all outgoing message and - // should treat any missing/empty value - // as CoT value "Undefined". - // A CoT/XML value of "Undefined" for this - // field should be conveyed in this message - // by omitting this value for compactness - string qos = 3; // optional - string opex = 4; // optional - string caveat = 16; // optional - string releaseableTo = 17; // optional - - string uid = 5; // - uint64 sendTime = 6; // converted to timeMs - uint64 startTime = 7; // converted to timeMs - uint64 staleTime = 8; // converted to timeMs - string how = 9; // - - // - double lat = 10; // - double lon = 11; // - double hae = 12; // use 999999 for unknown - double ce = 13; // use 999999 for unknown - double le = 14; // use 999999 for unknown - - // comprises children of - // This is optional - if omitted, then the cot message - // had no data under - Detail detail = 15; + // + + string type = 1; // + + string access = 2; // optional, but see below! + // field was optional in early + // cot implementations but now required + // in MIL-STD-6090. + // This message definition treats as + // "optional" due to legacy definition/use, + // but updated/new clients should be + // populating on all outgoing message and + // should treat any missing/empty value + // as CoT value "Undefined". + // A CoT/XML value of "Undefined" for this + // field should be conveyed in this message + // by omitting this value for compactness + string qos = 3; // optional + string opex = 4; // optional + string caveat = 16; // optional + string releaseableTo = 17; // optional + + string uid = 5; // + uint64 sendTime = 6; // converted to timeMs + uint64 startTime = 7; // converted to timeMs + uint64 staleTime = 8; // converted to timeMs + string how = 9; // + + // + double lat = 10; // + double lon = 11; // + double hae = 12; // use 999999 for unknown + double ce = 13; // use 999999 for unknown + double le = 14; // use 999999 for unknown + + // comprises children of + // This is optional - if omitted, then the cot message + // had no data under + Detail detail = 15; } diff --git a/protobuf/detail.proto b/protobuf/detail.proto index 8c2c3f2..402e7c4 100644 --- a/protobuf/detail.proto +++ b/protobuf/detail.proto @@ -50,23 +50,23 @@ import "track.proto"; // and the data in the equivalent message should ignored. message Detail { - string xmlDetail = 1; + string xmlDetail = 1; - // - Contact contact = 2; + // + Contact contact = 2; - // <__group> - Group group = 3; + // <__group> + Group group = 3; - // - PrecisionLocation precisionLocation = 4; + // + PrecisionLocation precisionLocation = 4; - // - Status status = 5; + // + Status status = 5; - // - Takv takv = 6; + // + Takv takv = 6; - // - Track track = 7; + // + Track track = 7; } diff --git a/protobuf/group.proto b/protobuf/group.proto index 97e59e0..8bd253c 100644 --- a/protobuf/group.proto +++ b/protobuf/group.proto @@ -8,6 +8,6 @@ option go_package = "github.com/kdudkov/goatak/cotproto"; // to the message format will be rejected and fall back to opaque // XML representation message Group { - string name = 1; // name= - string role = 2; // role= + string name = 1; // name= + string role = 2; // role= } diff --git a/protobuf/precisionlocation.proto b/protobuf/precisionlocation.proto index d2c9f8a..92dcd7a 100644 --- a/protobuf/precisionlocation.proto +++ b/protobuf/precisionlocation.proto @@ -7,6 +7,6 @@ option go_package = "github.com/kdudkov/goatak/cotproto"; // to the message format will be rejected and fall back to opaque // XML representation message PrecisionLocation { - string geopointsrc = 1; // geopointsrc= - string altsrc = 2; // altsrc= + string geopointsrc = 1; // geopointsrc= + string altsrc = 2; // altsrc= } diff --git a/protobuf/simple.proto b/protobuf/simple.proto index c022183..3b2c8c5 100644 --- a/protobuf/simple.proto +++ b/protobuf/simple.proto @@ -6,6 +6,6 @@ option go_package = "github.com/kdudkov/goatak/cotproto"; // to the message format will be rejected and fall back to opaque // XML representation message Simple { - string endpoint = 1; // endpoint= - string callsign = 2; // callsign= + string endpoint = 1; // endpoint= + string callsign = 2; // callsign= } \ No newline at end of file diff --git a/protobuf/status.proto b/protobuf/status.proto index 2c0dcc6..12528af 100644 --- a/protobuf/status.proto +++ b/protobuf/status.proto @@ -7,5 +7,5 @@ option go_package = "github.com/kdudkov/goatak/cotproto"; // to the message format will be rejected and fall back to opaque // XML representation message Status { - uint32 battery = 1; // battery= + uint32 battery = 1; // battery= } diff --git a/protobuf/takcontrol.proto b/protobuf/takcontrol.proto index e3ff6d0..bb6dd39 100644 --- a/protobuf/takcontrol.proto +++ b/protobuf/takcontrol.proto @@ -7,11 +7,11 @@ option go_package = "github.com/kdudkov/goatak/cotproto"; // of protocol elements this sender supports during // decoding. message TakControl { - // Lowest TAK protocol version supported - // If not filled in (reads as 0), version 1 is assumed - uint32 minProtoVersion = 1; + // Lowest TAK protocol version supported + // If not filled in (reads as 0), version 1 is assumed + uint32 minProtoVersion = 1; - // Highest TAK protocol version supported - // If not filled in (reads as 0), version 1 is assumed - uint32 maxProtoVersion = 2; + // Highest TAK protocol version supported + // If not filled in (reads as 0), version 1 is assumed + uint32 maxProtoVersion = 2; } diff --git a/protobuf/takmessage.proto b/protobuf/takmessage.proto index 7628681..0674f0c 100644 --- a/protobuf/takmessage.proto +++ b/protobuf/takmessage.proto @@ -7,14 +7,14 @@ import "takcontrol.proto"; // Top level message sent for TAK Messaging Protocol Version 1. message TakMessage { - // Optional - if omitted, continue using last reported control - // information - TakControl takControl = 1; + // Optional - if omitted, continue using last reported control + // information + TakControl takControl = 1; - // Optional - if omitted, no event data in this message - CotEvent cotEvent = 2; + // Optional - if omitted, no event data in this message + CotEvent cotEvent = 2; - uint64 submissionTime = 3; - uint64 creationTime = 4; + uint64 submissionTime = 3; + uint64 creationTime = 4; } diff --git a/protobuf/takv.proto b/protobuf/takv.proto index 041d187..ae617ee 100644 --- a/protobuf/takv.proto +++ b/protobuf/takv.proto @@ -7,8 +7,8 @@ option go_package = "github.com/kdudkov/goatak/cotproto"; // to the message format will be rejected and fall back to opaque // XML representation message Takv { - string device = 1; // device= - string platform = 2; // platform= - string os = 3; // os= - string version = 4; // version= + string device = 1; // device= + string platform = 2; // platform= + string os = 3; // os= + string version = 4; // version= } diff --git a/protobuf/track.proto b/protobuf/track.proto index 8287d6c..f9679f0 100644 --- a/protobuf/track.proto +++ b/protobuf/track.proto @@ -7,6 +7,6 @@ option go_package = "github.com/kdudkov/goatak/cotproto"; // to the message format will be rejected and fall back to opaque // XML representation message Track { - double speed = 1; // speed= - double course = 2; // course= + double speed = 1; // speed= + double course = 2; // course= } diff --git a/staticfiles/renderer.go b/staticfiles/renderer.go index 6b1dc9d..ded6631 100644 --- a/staticfiles/renderer.go +++ b/staticfiles/renderer.go @@ -63,6 +63,7 @@ func walkEmbed(fs embed.FS, fn func(fs embed.FS, fname string) error) error { path := dirs[i] dir, err := fs.ReadDir(path) + if err != nil { return err }