Add basic form of log redaction for user names and passwords (#1810)

This commit is contained in:
andig 2021-10-31 10:58:03 +01:00
parent cbadd13db1
commit ca3f793eb1
30 changed files with 92 additions and 36 deletions

View file

@ -75,7 +75,7 @@ func NewEaseeFromConfig(other map[string]interface{}) (api.Charger, error) {
// NewEasee creates Easee charger
func NewEasee(user, password, charger string, circuit int, cache time.Duration) (*Easee, error) {
log := util.NewLogger("easee")
log := util.NewLogger("easee").Redact(user, password)
if !sponsor.IsAuthorized() {
return nil, api.ErrSponsorRequired

View file

@ -69,7 +69,7 @@ func NewGoEFromConfig(other map[string]interface{}) (api.Charger, error) {
func NewGoE(uri, token string, cache time.Duration) (api.Charger, error) {
c := &GoE{}
log := util.NewLogger("go-e")
log := util.NewLogger("go-e").Redact(token)
if token != "" {
c.api = goe.NewCloud(log, token, cache)

View file

@ -39,7 +39,8 @@ func NewDiscovergyFromConfig(other map[string]interface{}) (api.Meter, error) {
return nil, err
}
log := util.NewLogger("discgy")
log := util.NewLogger("discgy").Redact(cc.User, cc.Password, cc.Meter)
client := request.NewHelper(log)
client.Transport = basicauth.NewTransport(cc.User, cc.Password, client.Transport)

View file

@ -19,5 +19,6 @@ func NewFritzDECTFromConfig(other map[string]interface{}) (api.Meter, error) {
if err := util.DecodeOther(other, &cc); err != nil {
return nil, err
}
return fritzdect.NewConnection(cc.URI, cc.AIN, cc.User, cc.Password)
}

View file

@ -48,7 +48,7 @@ func NewSMAFromConfig(other map[string]interface{}) (api.Meter, error) {
// NewSMA creates a SMA Meter
func NewSMA(uri, password, iface string, serial uint32, scale float64) (api.Meter, error) {
sm := &SMA{
log: util.NewLogger("sma"),
log: util.NewLogger("sma").Redact(password),
uri: uri,
scale: scale,
}

View file

@ -64,7 +64,7 @@ func NewTeslaFromConfig(other map[string]interface{}) (api.Meter, error) {
// NewTesla creates a Tesla Meter
func NewTesla(uri, usage, password string) (api.Meter, error) {
log := util.NewLogger("tesla")
log := util.NewLogger("tesla").Redact(password)
m := &Tesla{
Helper: request.NewHelper(log),

View file

@ -63,7 +63,7 @@ func NewConnection(uri, ain, user, password string) (*Connection, error) {
Password: password,
}
log := util.NewLogger("fritzdect")
log := util.NewLogger("fritzdect").Redact(password)
fritzdect := &Connection{
Helper: request.NewHelper(log),

View file

@ -3,7 +3,6 @@ package util
import (
"io"
"log"
"os"
"regexp"
"strconv"
"strings"
@ -32,6 +31,7 @@ var LogAreaPadding = 6
type Logger struct {
*jww.Notepad
name string
*Redactor
}
// NewLogger creates a logger with the given log area and adds it to the registry
@ -49,13 +49,17 @@ func NewLogger(area string) *Logger {
}
level := LogLevelForArea(area)
notepad := jww.NewNotepad(level, level, os.Stdout, io.Discard, padded, log.Ldate|log.Ltime)
redactor := new(Redactor)
notepad := jww.NewNotepad(level, level, redactor, io.Discard, padded, log.Ldate|log.Ltime)
logger := &Logger{
Notepad: notepad,
name: area,
Notepad: notepad,
Redactor: redactor,
name: area,
}
loggers[area] = logger
return logger
}
@ -64,6 +68,12 @@ func (l *Logger) Name() string {
return l.name
}
// Redact adds items for redaction
func (l *Logger) Redact(items ...string) *Logger {
l.Redactor.Redact(items...)
return l
}
// Loggers invokes callback for each configured logger
func Loggers(cb func(string, *Logger)) {
for name, logger := range loggers {

42
util/redactor.go Normal file
View file

@ -0,0 +1,42 @@
package util
import (
"bytes"
"net/url"
"os"
)
var (
// RedactReplacement is the default replacement string
RedactReplacement = "***"
// RedactHook is the hook for expanding different representations of
// redaction items. Setting to nil will disable redaction.
RedactHook = RedactDefaultHook
)
// Redactor implements a redacting io.Writer
type Redactor struct {
redact []string
}
// Redact adds items for redaction
func (l *Redactor) Redact(redact ...string) {
for _, s := range redact {
if RedactHook != nil && len(s) > 0 {
l.redact = append(l.redact, RedactHook(s)...)
}
}
}
func (l *Redactor) Write(p []byte) (n int, err error) {
for _, s := range l.redact {
p = bytes.ReplaceAll(p, []byte(s), []byte(RedactReplacement))
}
return os.Stdout.Write(p)
}
// RedactDefaultHook expands a redaction item to include URL encoding
func RedactDefaultHook(s string) []string {
return []string{s, url.QueryEscape(s)}
}

View file

@ -46,7 +46,7 @@ func NewAudiFromConfig(other map[string]interface{}) (api.Vehicle, error) {
embed: &cc.embed,
}
log := util.NewLogger("audi")
log := util.NewLogger("audi").Redact(cc.User, cc.Password, cc.VIN)
identity := vw.NewIdentity(log)
query := url.Values(map[string][]string{

View file

@ -38,7 +38,7 @@ func NewBMWFromConfig(other map[string]interface{}) (api.Vehicle, error) {
embed: &cc.embed,
}
log := util.NewLogger("bmw")
log := util.NewLogger("bmw").Redact(cc.User, cc.Password, cc.VIN)
identity := bmw.NewIdentity(log)
if err := identity.Login(cc.User, cc.Password); err != nil {

View file

@ -16,6 +16,7 @@ import (
)
const (
carwingsRequestTimeout = 90 * time.Second
carwingsStatusExpiry = 5 * time.Minute // if returned status value is older, evcc will init refresh
carwingsRefreshTimeout = 2 * time.Minute // timeout to get status after refresh
)
@ -54,17 +55,16 @@ func NewCarWingsFromConfig(other map[string]interface{}) (api.Vehicle, error) {
return nil, errors.New("missing credentials")
}
// http client with high dial/handshake timeout
const timeout = 90 * time.Second
log := util.NewLogger("carwings")
log := util.NewLogger("carwings").Redact(cc.User, cc.Password, cc.VIN)
// http client with high dial/handshake timeout
transport := request.NewTripper(log, &http.Transport{
Proxy: http.ProxyFromEnvironment, // default
DialContext: (&net.Dialer{
Timeout: timeout,
Timeout: carwingsRequestTimeout,
KeepAlive: 30 * time.Second, // default
}).DialContext,
TLSHandshakeTimeout: timeout,
TLSHandshakeTimeout: carwingsRequestTimeout,
ForceAttemptHTTP2: true, // default
MaxIdleConns: 100, // default
IdleConnTimeout: 90 * time.Second, // default
@ -72,7 +72,7 @@ func NewCarWingsFromConfig(other map[string]interface{}) (api.Vehicle, error) {
})
carwings.Client = &http.Client{
Timeout: timeout,
Timeout: carwingsRequestTimeout,
Transport: transport,
}

View file

@ -46,7 +46,7 @@ func NewEnyaqFromConfig(other map[string]interface{}) (api.Vehicle, error) {
}
var err error
log := util.NewLogger("enyaq")
log := util.NewLogger("enyaq").Redact(cc.User, cc.Password, cc.VIN)
if cc.VIN == "" {
identity := vw.NewIdentity(log)

View file

@ -47,7 +47,7 @@ func NewFiatFromConfig(other map[string]interface{}) (api.Vehicle, error) {
embed: &cc.embed,
}
log := util.NewLogger("fiat")
log := util.NewLogger("fiat").Redact(cc.User, cc.Password, cc.VIN)
identity := fiat.NewIdentity(log, cc.User, cc.Password)
err := identity.Login()

View file

@ -59,7 +59,7 @@ func NewFordFromConfig(other map[string]interface{}) (api.Vehicle, error) {
return nil, errors.New("missing credentials")
}
log := util.NewLogger("ford")
log := util.NewLogger("ford").Redact(cc.User, cc.Password, cc.VIN)
v := &Ford{
embed: &cc.embed,

View file

@ -40,7 +40,8 @@ func NewHyundaiFromConfig(other map[string]interface{}) (api.Vehicle, error) {
return nil, errors.New("missing credentials")
}
log := util.NewLogger("hyundai")
log := util.NewLogger("hyundai").Redact(cc.User, cc.Password, cc.VIN)
settings := bluelink.Config{
URI: "https://prd.eu-ccapi.hyundai.com:8080",
BasicToken: "NmQ0NzdjMzgtM2NhNC00Y2YzLTk1NTctMmExOTI5YTk0NjU0OktVeTQ5WHhQekxwTHVvSzB4aEJDNzdXNlZYaG10UVI5aVFobUlGampvWTRJcHhzVg==",

View file

@ -45,7 +45,7 @@ func NewIDFromConfig(other map[string]interface{}) (api.Vehicle, error) {
embed: &cc.embed,
}
log := util.NewLogger("id")
log := util.NewLogger("id").Redact(cc.User, cc.Password, cc.VIN)
identity := vw.NewIdentity(log)
query := url.Values(map[string][]string{

View file

@ -40,7 +40,8 @@ func NewKiaFromConfig(other map[string]interface{}) (api.Vehicle, error) {
return nil, errors.New("missing credentials")
}
log := util.NewLogger("kia")
log := util.NewLogger("kia").Redact(cc.User, cc.Password, cc.VIN)
settings := bluelink.Config{
URI: "https://prd.eu-ccapi.kia.com:8080",
BasicToken: "ZmRjODVjMDAtMGEyZi00YzY0LWJjYjQtMmNmYjE1MDA3MzBhOnNlY3JldA==",

View file

@ -48,7 +48,7 @@ func NewNissanFromConfig(other map[string]interface{}) (api.Vehicle, error) {
embed: &cc.embed,
}
log := util.NewLogger("nissan")
log := util.NewLogger("nissan").Redact(cc.User, cc.Password, cc.VIN)
identity := nissan.NewIdentity(log)
if err := identity.Login(cc.User, cc.Password); err != nil {

View file

@ -48,7 +48,7 @@ func NewNiuFromConfig(other map[string]interface{}) (api.Vehicle, error) {
return nil, errors.New("missing user, password or serial")
}
log := util.NewLogger("niu")
log := util.NewLogger("niu").Redact(cc.User, cc.Password)
v := &Niu{
embed: &cc.embed,

View file

@ -60,7 +60,7 @@ func NewOvmsFromConfig(other map[string]interface{}) (api.Vehicle, error) {
return nil, err
}
log := util.NewLogger("ovms")
log := util.NewLogger("ovms").Redact(cc.User, cc.Password, cc.VehicleID)
v := &Ovms{
embed: &cc.embed,

View file

@ -38,12 +38,11 @@ func NewPorscheFromConfig(other map[string]interface{}) (api.Vehicle, error) {
Cache: interval,
}
log := util.NewLogger("porsche")
if err := util.DecodeOther(other, &cc); err != nil {
return nil, err
}
log := util.NewLogger("porsche").Redact(cc.User, cc.Password, cc.VIN)
identity := porsche.NewIdentity(log, cc.User, cc.Password)
accessTokens, err := identity.Login()

View file

@ -85,6 +85,7 @@ func newPSA(log *util.Logger, brand, realm, id, secret string, other map[string]
embed: &cc.embed,
}
log.Redact(cc.User, cc.Password, cc.VIN)
identity := psa.NewIdentity(log, brand, cc.Credentials.ID, cc.Credentials.Secret)
if err := identity.Login(cc.User, cc.Password); err != nil {

View file

@ -128,7 +128,7 @@ func NewRenaultFromConfig(other map[string]interface{}) (api.Vehicle, error) {
return nil, err
}
log := util.NewLogger("renault")
log := util.NewLogger("renault").Redact(cc.User, cc.Password, cc.VIN)
v := &Renault{
embed: &cc.embed,

View file

@ -45,7 +45,7 @@ func NewSeatFromConfig(other map[string]interface{}) (api.Vehicle, error) {
embed: &cc.embed,
}
log := util.NewLogger("seat")
log := util.NewLogger("seat").Redact(cc.User, cc.Password, cc.VIN)
identity := vw.NewIdentity(log)
query := url.Values(map[string][]string{

View file

@ -45,7 +45,7 @@ func NewSkodaFromConfig(other map[string]interface{}) (api.Vehicle, error) {
embed: &cc.embed,
}
log := util.NewLogger("skoda")
log := util.NewLogger("skoda").Redact(cc.User, cc.Password, cc.VIN)
identity := vw.NewIdentity(log)
query := url.Values(map[string][]string{

View file

@ -50,7 +50,7 @@ func NewTeslaFromConfig(other map[string]interface{}) (api.Vehicle, error) {
}
// authenticated http client with logging injected to the Tesla client
log := util.NewLogger("tesla")
log := util.NewLogger("tesla").Redact(cc.Tokens.Access, cc.Tokens.Refresh)
ctx := context.WithValue(context.Background(), oauth2.HTTPClient, request.NewHelper(log).Client)
options := []tesla.ClientOption{tesla.WithToken(&oauth2.Token{

View file

@ -77,7 +77,7 @@ func NewTronityFromConfig(other map[string]interface{}) (api.Vehicle, error) {
}
// authenticated http client with logging injected to the tronity client
log := util.NewLogger("tronity")
log := util.NewLogger("tronity").Redact(cc.Credentials.ID, cc.Credentials.Secret)
oc, err := tronity.OAuth2Config(cc.Credentials.ID, cc.Credentials.Secret)
if err != nil {

View file

@ -108,7 +108,7 @@ func NewVolvoFromConfig(other map[string]interface{}) (api.Vehicle, error) {
return nil, err
}
log := util.NewLogger("volvo")
log := util.NewLogger("volvo").Redact(cc.User, cc.Password, cc.VIN)
v := &Volvo{
embed: &cc.embed,

View file

@ -45,7 +45,7 @@ func NewVWFromConfig(other map[string]interface{}) (api.Vehicle, error) {
embed: &cc.embed,
}
log := util.NewLogger("vw")
log := util.NewLogger("vw").Redact(cc.User, cc.Password, cc.VIN)
identity := vw.NewIdentity(log)
query := url.Values(map[string][]string{