fix(database/influxdb): replace invisible chars and whitespaces with space (#235)

This fixes issues where users use '\n' in tag values (e.g. the owner)
that is incompatible with InfluxDB's Line protocol.
This commit is contained in:
Grische 2024-06-11 17:11:34 +02:00 committed by GitHub
parent 9e13f41143
commit ef3ee358d1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 63 additions and 1 deletions

View File

@ -1,8 +1,10 @@
package influxdb
import (
"strings"
"sync"
"time"
"unicode"
"github.com/bdlm/log"
"github.com/influxdata/influxdb1-client/models"
@ -94,6 +96,25 @@ func Connect(configuration map[string]interface{}) (database.Connection, error)
return db, nil
}
func sanitizeValues(tags models.Tags) models.Tags {
// https://docs.influxdata.com/influxdb/v2/reference/syntax/line-protocol/
// Line protocol does not support the newline character \n in tag or field values.
// To be safe, remove all non-printable characters and spaces except ASCII space and U+0020.
for _, tag := range tags {
cleaned_value := strings.Map(func(r rune) rune {
if unicode.IsPrint(r) {
return r
}
return ' '
}, string(tag.Value))
if cleaned_value != string(tag.Value) {
tags.SetString(string(tag.Key), cleaned_value)
}
}
return tags
}
func (conn *Connection) addPoint(name string, tags models.Tags, fields models.Fields, t ...time.Time) {
if configTags := conn.config.Tags(); configTags != nil {
for tag, valueInterface := range configTags {
@ -107,6 +128,9 @@ func (conn *Connection) addPoint(name string, tags models.Tags, fields models.Fi
}
}
}
tags = sanitizeValues(tags)
point, err := client.NewPoint(name, tags.Map(), fields, t...)
if err != nil {
log.Panicf("could not save points: %s", err)

View File

@ -7,7 +7,7 @@ import (
"time"
"github.com/influxdata/influxdb1-client/models"
"github.com/influxdata/influxdb1-client/v2"
client "github.com/influxdata/influxdb1-client/v2"
"github.com/stretchr/testify/assert"
)
@ -98,3 +98,41 @@ func TestAddPoint(t *testing.T) {
connection.addPoint("name", models.Tags{}, nil, time.Now())
})
}
func TestAddPointWithInvalidCharacters(t *testing.T) {
assert := assert.New(t)
connection := &Connection{
config: map[string]interface{}{},
points: make(chan *client.Point, 1),
}
tagsOrigin := models.Tags{}
tagsOrigin.SetString("owner", "\u00a0this owner\nuses invalid chars\t")
connection.addPoint("name", tagsOrigin, models.Fields{"clients.total": 10}, time.Now())
point := <-connection.points
assert.NotNil(point)
tags := point.Tags()
assert.NotNil(tags)
assert.Equal(tags["owner"], " this owner uses invalid chars ")
}
func TestAddPointWithValidCharacters(t *testing.T) {
assert := assert.New(t)
connection := &Connection{
config: map[string]interface{}{},
points: make(chan *client.Point, 1),
}
tagsOrigin := models.Tags{}
tagsOrigin.SetString("owner", "📶this owner uses only\u0020valid chars🛜")
connection.addPoint("name", tagsOrigin, models.Fields{"clients.total": 10}, time.Now())
point := <-connection.points
assert.NotNil(point)
tags := point.Tags()
assert.NotNil(tags)
assert.Equal(tags["owner"], "📶this owner uses only\u0020valid chars🛜")
}