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;
- //