From d96f841befdba787ac6903a56b481ea775843f9e Mon Sep 17 00:00:00 2001 From: Patrick Pacher Date: Wed, 6 Sep 2023 17:08:04 +0200 Subject: [PATCH 01/13] Add support for $gt, $ge, $lt, $le operators for netquery. Update DatetimeEncoder to support values specified in seconds --- netquery/orm/encoder.go | 5 ++++ netquery/query.go | 55 +++++++++++++++++++++++++++++++++++------ 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/netquery/orm/encoder.go b/netquery/orm/encoder.go index ef86b842..ff30a14a 100644 --- a/netquery/orm/encoder.go +++ b/netquery/orm/encoder.go @@ -156,6 +156,8 @@ func DatetimeEncoder(loc *time.Location) EncodeFunc { val = reflect.Indirect(val) } + normalizedKind := normalizeKind(valType.Kind()) + // we only care about "time.Time" here var t time.Time switch { @@ -179,6 +181,9 @@ func DatetimeEncoder(loc *time.Location) EncodeFunc { return nil, false, fmt.Errorf("failed to parse time as RFC3339: %w", err) } + case (normalizedKind == reflect.Int || normalizedKind == reflect.Uint || normalizedKind == reflect.Float32) && colDef.IsTime: + t = time.Unix(val.Int(), 0) + default: // we don't care ... return nil, false, nil diff --git a/netquery/query.go b/netquery/query.go index 1e60b7fa..8ff99fe3 100644 --- a/netquery/query.go +++ b/netquery/query.go @@ -38,11 +38,15 @@ type ( Equal interface{} Matcher struct { - Equal interface{} `json:"$eq,omitempty"` - NotEqual interface{} `json:"$ne,omitempty"` - In []interface{} `json:"$in,omitempty"` - NotIn []interface{} `json:"$notIn,omitempty"` - Like string `json:"$like,omitempty"` + Equal interface{} `json:"$eq,omitempty"` + NotEqual interface{} `json:"$ne,omitempty"` + In []interface{} `json:"$in,omitempty"` + NotIn []interface{} `json:"$notIn,omitempty"` + Like string `json:"$like,omitempty"` + Greater *float64 `json:"$gt,omitempty"` + GreaterOrEqual *float64 `json:"$ge,omitempty"` + Less *float64 `json:"$lt,omitempty"` + LessOrEqual *float64 `json:"$le,omitempty"` } Count struct { @@ -258,6 +262,22 @@ func (match Matcher) Validate() error { found++ } + if match.Greater != nil { + found++ + } + + if match.GreaterOrEqual != nil { + found++ + } + + if match.Less != nil { + found++ + } + + if match.LessOrEqual != nil { + found++ + } + if found == 0 { return fmt.Errorf("no conditions specified") } @@ -318,10 +338,15 @@ func (match Matcher) toSQLConditionClause(ctx context.Context, suffix string, co params[uniqKey] = encodedValue } + nameStmt := colDef.Name + if colDef.IsTime && colDef.Type == sqlite.TypeText { + nameStmt = fmt.Sprintf("strftime('%%s', %s)+0", nameStmt) + } + if len(placeholder) == 1 && !list { - queryParts = append(queryParts, fmt.Sprintf("%s %s %s", colDef.Name, operator, placeholder[0])) + queryParts = append(queryParts, fmt.Sprintf("%s %s %s", nameStmt, operator, placeholder[0])) } else { - queryParts = append(queryParts, fmt.Sprintf("%s %s ( %s )", colDef.Name, operator, strings.Join(placeholder, ", "))) + queryParts = append(queryParts, fmt.Sprintf("%s %s ( %s )", nameStmt, operator, strings.Join(placeholder, ", "))) } } @@ -345,6 +370,22 @@ func (match Matcher) toSQLConditionClause(ctx context.Context, suffix string, co add("LIKE", "like", false, match.Like) } + if match.Greater != nil { + add(">", "gt", false, *match.Greater) + } + + if match.GreaterOrEqual != nil { + add(">=", "ge", false, *match.GreaterOrEqual) + } + + if match.Less != nil { + add("<", "lt", false, *match.Less) + } + + if match.LessOrEqual != nil { + add("<=", "le", false, *match.LessOrEqual) + } + if len(queryParts) == 0 { // this is an empty matcher without a single condition. // we convert that to a no-op TRUE value From 4cd6823066d33603918b1fac2327c4ea25c5353a Mon Sep 17 00:00:00 2001 From: Patrick Pacher Date: Thu, 7 Sep 2023 11:58:07 +0200 Subject: [PATCH 02/13] Update netquery query handler to only use strftime when the given value is a number kind --- netquery/orm/decoder.go | 6 +++--- netquery/orm/encoder.go | 4 ++-- netquery/orm/schema_builder.go | 2 +- netquery/query.go | 20 +++++++++++++++++++- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/netquery/orm/decoder.go b/netquery/orm/decoder.go index 24126e97..5b87df82 100644 --- a/netquery/orm/decoder.go +++ b/netquery/orm/decoder.go @@ -289,7 +289,7 @@ func decodeBasic() DecodeFunc { // if we have the column definition available we // use the target go type from there. if colDef != nil { - valueKind = normalizeKind(colDef.GoType.Kind()) + valueKind = NormalizeKind(colDef.GoType.Kind()) // if we have a column definition we try to convert the value to // the actual Go-type that was used in the model. @@ -458,10 +458,10 @@ func runDecodeHooks(colIdx int, colDef *ColumnDef, stmt Stmt, fieldDef reflect.S // to their base type. func getKind(val reflect.Value) reflect.Kind { kind := val.Kind() - return normalizeKind(kind) + return NormalizeKind(kind) } -func normalizeKind(kind reflect.Kind) reflect.Kind { +func NormalizeKind(kind reflect.Kind) reflect.Kind { switch { case kind >= reflect.Int && kind <= reflect.Int64: return reflect.Int diff --git a/netquery/orm/encoder.go b/netquery/orm/encoder.go index ff30a14a..a1b880b7 100644 --- a/netquery/orm/encoder.go +++ b/netquery/orm/encoder.go @@ -123,7 +123,7 @@ func encodeBasic() EncodeFunc { val = val.Elem() } - switch normalizeKind(kind) { //nolint:exhaustive + switch NormalizeKind(kind) { //nolint:exhaustive case reflect.String, reflect.Float64, reflect.Bool, @@ -156,7 +156,7 @@ func DatetimeEncoder(loc *time.Location) EncodeFunc { val = reflect.Indirect(val) } - normalizedKind := normalizeKind(valType.Kind()) + normalizedKind := NormalizeKind(valType.Kind()) // we only care about "time.Time" here var t time.Time diff --git a/netquery/orm/schema_builder.go b/netquery/orm/schema_builder.go index 6aba2a1f..018a55e1 100644 --- a/netquery/orm/schema_builder.go +++ b/netquery/orm/schema_builder.go @@ -176,7 +176,7 @@ func getColumnDef(fieldType reflect.StructField) (*ColumnDef, error) { } def.GoType = ft - kind := normalizeKind(ft.Kind()) + kind := NormalizeKind(ft.Kind()) switch kind { //nolint:exhaustive case reflect.Int, reflect.Uint: diff --git a/netquery/query.go b/netquery/query.go index 8ff99fe3..33a9ae40 100644 --- a/netquery/query.go +++ b/netquery/query.go @@ -5,10 +5,12 @@ import ( "encoding/json" "fmt" "io" + "reflect" "sort" "strings" "github.com/hashicorp/go-multierror" + "golang.org/x/exp/slices" "zombiezen.com/go/sqlite" "github.com/safing/portmaster/netquery/orm" @@ -338,8 +340,24 @@ func (match Matcher) toSQLConditionClause(ctx context.Context, suffix string, co params[uniqKey] = encodedValue } + // NOTE(ppacher): for now we assume that the type of each member of values + // is the same. We also can be sure that there is always at least one value. + // + // FIXME(ppacher): if we start supporting values of different types here + // we need to revisit the whole behavior as we might need to do more boolean + // expression nesting to support that. + kind := orm.NormalizeKind(reflect.TypeOf(values[0]).Kind()) + isNumber := slices.Contains([]reflect.Kind{ + reflect.Uint, + reflect.Int, + reflect.Float64, + }, kind) + + // if this is a time column that is stored in "text" format and the provided + // value is a number type, we need to wrap the property in a strftime() method + // call. nameStmt := colDef.Name - if colDef.IsTime && colDef.Type == sqlite.TypeText { + if colDef.IsTime && colDef.Type == sqlite.TypeText && isNumber { nameStmt = fmt.Sprintf("strftime('%%s', %s)+0", nameStmt) } From 87f19bdcc245e0efba2fc7fb5b172b8abc145f73 Mon Sep 17 00:00:00 2001 From: Patrick Pacher Date: Thu, 7 Sep 2023 11:59:36 +0200 Subject: [PATCH 03/13] Fix incorrect check using reflect.Float32 instead of reflect.Float64 --- netquery/orm/encoder.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netquery/orm/encoder.go b/netquery/orm/encoder.go index a1b880b7..6ae8fb1b 100644 --- a/netquery/orm/encoder.go +++ b/netquery/orm/encoder.go @@ -181,7 +181,7 @@ func DatetimeEncoder(loc *time.Location) EncodeFunc { return nil, false, fmt.Errorf("failed to parse time as RFC3339: %w", err) } - case (normalizedKind == reflect.Int || normalizedKind == reflect.Uint || normalizedKind == reflect.Float32) && colDef.IsTime: + case (normalizedKind == reflect.Int || normalizedKind == reflect.Uint || normalizedKind == reflect.Float64) && colDef.IsTime: t = time.Unix(val.Int(), 0) default: From c58a73081f4b0075e407c65ae06beb61bb1094fe Mon Sep 17 00:00:00 2001 From: Patrick Pacher Date: Wed, 13 Sep 2023 10:27:00 +0200 Subject: [PATCH 04/13] netquery: fix value encoding for time.Time queries --- netquery/orm/encoder.go | 12 +++++++++++- netquery/query.go | 32 +++++++++++++++++++++++++------- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/netquery/orm/encoder.go b/netquery/orm/encoder.go index 6ae8fb1b..107f9f77 100644 --- a/netquery/orm/encoder.go +++ b/netquery/orm/encoder.go @@ -182,7 +182,17 @@ func DatetimeEncoder(loc *time.Location) EncodeFunc { } case (normalizedKind == reflect.Int || normalizedKind == reflect.Uint || normalizedKind == reflect.Float64) && colDef.IsTime: - t = time.Unix(val.Int(), 0) + seconds := int64(0) + switch normalizedKind { + case reflect.Int: + seconds = val.Int() + case reflect.Uint: + seconds = int64(val.Uint()) + case reflect.Float64: + seconds = int64(val.Float()) + } + + t = time.Unix(seconds, 0) default: // we don't care ... diff --git a/netquery/query.go b/netquery/query.go index 33a9ae40..edbf3309 100644 --- a/netquery/query.go +++ b/netquery/query.go @@ -327,12 +327,30 @@ func (match Matcher) toSQLConditionClause(ctx context.Context, suffix string, co var placeholder []string for idx, value := range values { - encodedValue, err := orm.EncodeValue(ctx, &colDef, value, encoderConfig) - if err != nil { - errs.Errors = append(errs.Errors, - fmt.Errorf("failed to encode %v for column %s: %w", value, colDef.Name, err), - ) - return + var ( + encodedValue any = value + err error + ) + + kind := orm.NormalizeKind(reflect.TypeOf(value).Kind()) + isNumber := slices.Contains([]reflect.Kind{ + reflect.Uint, + reflect.Int, + reflect.Float64, + }, kind) + + // if we query a time-field that is queried as a number, don't do any encoding + // here as the orm.DateTimeEncoder would convert the number to a string. + if colDef.IsTime && colDef.Type == sqlite.TypeText && isNumber { + encodedValue = value + } else { + encodedValue, err = orm.EncodeValue(ctx, &colDef, value, encoderConfig) + if err != nil { + errs.Errors = append(errs.Errors, + fmt.Errorf("failed to encode %v for column %s: %w", value, colDef.Name, err), + ) + return + } } uniqKey := fmt.Sprintf(":%s%s%d", key, suffix, idx) @@ -340,7 +358,7 @@ func (match Matcher) toSQLConditionClause(ctx context.Context, suffix string, co params[uniqKey] = encodedValue } - // NOTE(ppacher): for now we assume that the type of each member of values + // NOTE(ppacher): for now we assume that the type of each element of values // is the same. We also can be sure that there is always at least one value. // // FIXME(ppacher): if we start supporting values of different types here From d5c4495991312b69bbd844d7757f7127ffc8482c Mon Sep 17 00:00:00 2001 From: Patrick Pacher Date: Wed, 13 Sep 2023 10:27:29 +0200 Subject: [PATCH 05/13] core: add core/localeID setting to configure formating of dates, currencies and numbers for the user interface --- core/config.go | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/core/config.go b/core/config.go index 31eb3c28..7a549409 100644 --- a/core/config.go +++ b/core/config.go @@ -13,6 +13,8 @@ var ( CfgNetworkServiceKey = "core/networkService" defaultNetworkServiceMode bool + + CfgLocaleKey = "core/localeID" ) func init() { @@ -41,5 +43,32 @@ func registerConfig() error { return err } + if err := config.Register(&config.Option{ + Name: "Locale", + Key: CfgLocaleKey, + Description: "Configures the locale for the user interface. This mainly affects rendering of dates, currency and numbers. Note that the Portmaster does not yet support different languages.", + OptType: config.OptTypeString, + ExpertiseLevel: config.ExpertiseLevelUser, + ReleaseLevel: config.ReleaseLevelStable, + DefaultValue: "en-GB", + PossibleValues: []config.PossibleValue{ + { + Name: "en-GB", + Value: "en-GB", + }, + { + Name: "en-US", + Value: "en-US", + }, + }, + Annotations: config.Annotations{ + config.CategoryAnnotation: "User Interface", + config.DisplayHintAnnotation: config.DisplayHintOneOf, + config.RequiresUIReloadAnnotation: true, + }, + }); err != nil { + return err + } + return nil } From ba72c204d3ea9f53b4793b10149b9a18abd6a369 Mon Sep 17 00:00:00 2001 From: Patrick Pacher Date: Thu, 14 Sep 2023 08:39:15 +0200 Subject: [PATCH 06/13] netquery: split up query payload into a dedicated file --- netquery/query.go | 17 --- netquery/query_handler.go | 277 +--------------------------------- netquery/query_request.go | 304 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 306 insertions(+), 292 deletions(-) create mode 100644 netquery/query_request.go diff --git a/netquery/query.go b/netquery/query.go index edbf3309..a4502849 100644 --- a/netquery/query.go +++ b/netquery/query.go @@ -86,23 +86,6 @@ type ( Value string `json:"value"` } - QueryRequestPayload struct { - Select Selects `json:"select"` - Query Query `json:"query"` - OrderBy OrderBys `json:"orderBy"` - GroupBy []string `json:"groupBy"` - TextSearch *TextSearch `json:"textSearch"` - // A list of databases to query. If left empty, - // both, the LiveDatabase and the HistoryDatabase are queried - Databases []DatabaseName `json:"databases"` - - Pagination - - selectedFields []string - whitelistedFields []string - paramMap map[string]interface{} - } - QueryActiveConnectionChartPayload struct { Query Query `json:"query"` TextSearch *TextSearch `json:"textSearch"` diff --git a/netquery/query_handler.go b/netquery/query_handler.go index bca2eac3..bf2933d5 100644 --- a/netquery/query_handler.go +++ b/netquery/query_handler.go @@ -2,7 +2,6 @@ package netquery import ( "bytes" - "context" "encoding/json" "errors" "fmt" @@ -12,8 +11,6 @@ import ( "strings" "time" - "golang.org/x/exp/slices" - "github.com/safing/portbase/log" "github.com/safing/portmaster/netquery/orm" ) @@ -32,7 +29,7 @@ type ( func (qh *QueryHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) { start := time.Now() - requestPayload, err := qh.parseRequest(req) + requestPayload, err := parseQueryRequestPayload(req) if err != nil { http.Error(resp, err.Error(), http.StatusBadRequest) @@ -108,7 +105,7 @@ func (qh *QueryHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) { } } -func (qh *QueryHandler) parseRequest(req *http.Request) (*QueryRequestPayload, error) { //nolint:dupl +func parseQueryRequestPayload(req *http.Request) (*QueryRequestPayload, error) { //nolint:dupl var body io.Reader switch req.Method { @@ -138,275 +135,5 @@ func (qh *QueryHandler) parseRequest(req *http.Request) (*QueryRequestPayload, e return &requestPayload, nil } -func (req *QueryRequestPayload) generateSQL(ctx context.Context, schema *orm.TableSchema) (string, map[string]interface{}, error) { - if err := req.prepareSelectedFields(ctx, schema); err != nil { - return "", nil, fmt.Errorf("perparing selected fields: %w", err) - } - - // build the SQL where clause from the payload query - whereClause, paramMap, err := req.Query.toSQLWhereClause( - ctx, - "", - schema, - orm.DefaultEncodeConfig, - ) - if err != nil { - return "", nil, fmt.Errorf("generating where clause: %w", err) - } - - req.mergeParams(paramMap) - - if req.TextSearch != nil { - textClause, textParams, err := req.TextSearch.toSQLConditionClause(ctx, schema, "", orm.DefaultEncodeConfig) - if err != nil { - return "", nil, fmt.Errorf("generating text-search clause: %w", err) - } - - if textClause != "" { - if whereClause != "" { - whereClause += " AND " - } - - whereClause += textClause - - req.mergeParams(textParams) - } - } - - groupByClause, err := req.generateGroupByClause(schema) - if err != nil { - return "", nil, fmt.Errorf("generating group-by clause: %w", err) - } - - orderByClause, err := req.generateOrderByClause(schema) - if err != nil { - return "", nil, fmt.Errorf("generating order-by clause: %w", err) - } - - selectClause := req.generateSelectClause() - - if whereClause != "" { - whereClause = "WHERE " + whereClause - } - - // if no database is specified we default to LiveDatabase only. - if len(req.Databases) == 0 { - req.Databases = []DatabaseName{LiveDatabase} - } - - sources := make([]string, len(req.Databases)) - for idx, db := range req.Databases { - sources[idx] = fmt.Sprintf("SELECT * FROM %s.connections %s", db, whereClause) - } - - source := strings.Join(sources, " UNION ") - - query := `SELECT ` + selectClause + ` FROM ( ` + source + ` ) ` - - query += " " + groupByClause + " " + orderByClause + " " + req.Pagination.toSQLLimitOffsetClause() - - return strings.TrimSpace(query), req.paramMap, nil -} - -func (req *QueryRequestPayload) prepareSelectedFields(ctx context.Context, schema *orm.TableSchema) error { - for idx, s := range req.Select { - var field string - - switch { - case s.Count != nil: - field = s.Count.Field - case s.Distinct != nil: - field = *s.Distinct - case s.Sum != nil: - if s.Sum.Field != "" { - field = s.Sum.Field - } else { - field = "*" - } - case s.Min != nil: - if s.Min.Field != "" { - field = s.Min.Field - } else { - field = "*" - } - default: - field = s.Field - } - - colName := "*" - if field != "*" || (s.Count == nil && s.Sum == nil) { - var err error - - colName, err = req.validateColumnName(schema, field) - if err != nil { - return err - } - } - - switch { - case s.Count != nil: - as := s.Count.As - if as == "" { - as = fmt.Sprintf("%s_count", colName) - } - distinct := "" - if s.Count.Distinct { - distinct = "DISTINCT " - } - req.selectedFields = append( - req.selectedFields, - fmt.Sprintf("COUNT(%s%s) AS %s", distinct, colName, as), - ) - req.whitelistedFields = append(req.whitelistedFields, as) - - case s.Sum != nil: - if s.Sum.As == "" { - return fmt.Errorf("missing 'as' for $sum") - } - - var ( - clause string - params map[string]any - ) - - if s.Sum.Field != "" { - clause = s.Sum.Field - } else { - var err error - clause, params, err = s.Sum.Condition.toSQLWhereClause(ctx, fmt.Sprintf("sel%d", idx), schema, orm.DefaultEncodeConfig) - if err != nil { - return fmt.Errorf("in $sum: %w", err) - } - } - - req.mergeParams(params) - req.selectedFields = append( - req.selectedFields, - fmt.Sprintf("SUM(%s) AS %s", clause, s.Sum.As), - ) - req.whitelistedFields = append(req.whitelistedFields, s.Sum.As) - - case s.Min != nil: - if s.Min.As == "" { - return fmt.Errorf("missing 'as' for $min") - } - - var ( - clause string - params map[string]any - ) - - if s.Min.Field != "" { - clause = field - } else { - var err error - clause, params, err = s.Min.Condition.toSQLWhereClause(ctx, fmt.Sprintf("sel%d", idx), schema, orm.DefaultEncodeConfig) - if err != nil { - return fmt.Errorf("in $min: %w", err) - } - } - - req.mergeParams(params) - req.selectedFields = append( - req.selectedFields, - fmt.Sprintf("MIN(%s) AS %s", clause, s.Min.As), - ) - req.whitelistedFields = append(req.whitelistedFields, s.Min.As) - - case s.Distinct != nil: - req.selectedFields = append(req.selectedFields, fmt.Sprintf("DISTINCT %s", colName)) - req.whitelistedFields = append(req.whitelistedFields, colName) - - default: - req.selectedFields = append(req.selectedFields, colName) - } - } - - return nil -} - -func (req *QueryRequestPayload) mergeParams(params map[string]any) { - if req.paramMap == nil { - req.paramMap = make(map[string]any) - } - - for key, value := range params { - req.paramMap[key] = value - } -} - -func (req *QueryRequestPayload) generateGroupByClause(schema *orm.TableSchema) (string, error) { - if len(req.GroupBy) == 0 { - return "", nil - } - - groupBys := make([]string, len(req.GroupBy)) - for idx, name := range req.GroupBy { - colName, err := req.validateColumnName(schema, name) - if err != nil { - return "", err - } - - groupBys[idx] = colName - } - groupByClause := "GROUP BY " + strings.Join(groupBys, ", ") - - // if there are no explicitly selected fields we default to the - // group-by columns as that's what's expected most of the time anyway... - if len(req.selectedFields) == 0 { - req.selectedFields = append(req.selectedFields, groupBys...) - } - - return groupByClause, nil -} - -func (req *QueryRequestPayload) generateSelectClause() string { - selectClause := "*" - if len(req.selectedFields) > 0 { - selectClause = strings.Join(req.selectedFields, ", ") - } - - return selectClause -} - -func (req *QueryRequestPayload) generateOrderByClause(schema *orm.TableSchema) (string, error) { - if len(req.OrderBy) == 0 { - return "", nil - } - - orderBys := make([]string, len(req.OrderBy)) - for idx, sort := range req.OrderBy { - colName, err := req.validateColumnName(schema, sort.Field) - if err != nil { - return "", err - } - - if sort.Desc { - orderBys[idx] = fmt.Sprintf("%s DESC", colName) - } else { - orderBys[idx] = fmt.Sprintf("%s ASC", colName) - } - } - - return "ORDER BY " + strings.Join(orderBys, ", "), nil -} - -func (req *QueryRequestPayload) validateColumnName(schema *orm.TableSchema, field string) (string, error) { - colDef := schema.GetColumnDef(field) - if colDef != nil { - return colDef.Name, nil - } - - if slices.Contains(req.whitelistedFields, field) { - return field, nil - } - - if slices.Contains(req.selectedFields, field) { - return field, nil - } - - return "", fmt.Errorf("column name %q not allowed", field) -} - // Compile time check. var _ http.Handler = new(QueryHandler) diff --git a/netquery/query_request.go b/netquery/query_request.go new file mode 100644 index 00000000..e294d6ea --- /dev/null +++ b/netquery/query_request.go @@ -0,0 +1,304 @@ +package netquery + +import ( + "context" + "fmt" + "strings" + + "github.com/safing/portmaster/netquery/orm" + "golang.org/x/exp/slices" +) + +type ( + QueryRequestPayload struct { + Select Selects `json:"select"` + Query Query `json:"query"` + OrderBy OrderBys `json:"orderBy"` + GroupBy []string `json:"groupBy"` + TextSearch *TextSearch `json:"textSearch"` + // A list of databases to query. If left empty, + // both, the LiveDatabase and the HistoryDatabase are queried + Databases []DatabaseName `json:"databases"` + + Pagination + + selectedFields []string + whitelistedFields []string + paramMap map[string]interface{} + } + + // BatchQueryRequestPayload describes the payload of a batch netquery + // query. The map key is used in the response to identify the results + // for each query of the batch request. + BatchQueryRequestPayload map[string]QueryRequestPayload +) + +func (req *QueryRequestPayload) generateSQL(ctx context.Context, schema *orm.TableSchema) (string, map[string]interface{}, error) { + if err := req.prepareSelectedFields(ctx, schema); err != nil { + return "", nil, fmt.Errorf("perparing selected fields: %w", err) + } + + // build the SQL where clause from the payload query + whereClause, paramMap, err := req.Query.toSQLWhereClause( + ctx, + "", + schema, + orm.DefaultEncodeConfig, + ) + if err != nil { + return "", nil, fmt.Errorf("generating where clause: %w", err) + } + + req.mergeParams(paramMap) + + if req.TextSearch != nil { + textClause, textParams, err := req.TextSearch.toSQLConditionClause(ctx, schema, "", orm.DefaultEncodeConfig) + if err != nil { + return "", nil, fmt.Errorf("generating text-search clause: %w", err) + } + + if textClause != "" { + if whereClause != "" { + whereClause += " AND " + } + + whereClause += textClause + + req.mergeParams(textParams) + } + } + + groupByClause, err := req.generateGroupByClause(schema) + if err != nil { + return "", nil, fmt.Errorf("generating group-by clause: %w", err) + } + + orderByClause, err := req.generateOrderByClause(schema) + if err != nil { + return "", nil, fmt.Errorf("generating order-by clause: %w", err) + } + + selectClause := req.generateSelectClause() + + if whereClause != "" { + whereClause = "WHERE " + whereClause + } + + // if no database is specified we default to LiveDatabase only. + if len(req.Databases) == 0 { + req.Databases = []DatabaseName{LiveDatabase} + } + + sources := make([]string, len(req.Databases)) + for idx, db := range req.Databases { + sources[idx] = fmt.Sprintf("SELECT * FROM %s.connections %s", db, whereClause) + } + + source := strings.Join(sources, " UNION ") + + query := `SELECT ` + selectClause + ` FROM ( ` + source + ` ) ` + + query += " " + groupByClause + " " + orderByClause + " " + req.Pagination.toSQLLimitOffsetClause() + + return strings.TrimSpace(query), req.paramMap, nil +} + +func (req *QueryRequestPayload) prepareSelectedFields(ctx context.Context, schema *orm.TableSchema) error { + for idx, s := range req.Select { + var field string + + switch { + case s.Count != nil: + field = s.Count.Field + case s.Distinct != nil: + field = *s.Distinct + case s.Sum != nil: + if s.Sum.Field != "" { + field = s.Sum.Field + } else { + field = "*" + } + case s.Min != nil: + if s.Min.Field != "" { + field = s.Min.Field + } else { + field = "*" + } + default: + field = s.Field + } + + colName := "*" + if field != "*" || (s.Count == nil && s.Sum == nil) { + var err error + + colName, err = req.validateColumnName(schema, field) + if err != nil { + return err + } + } + + switch { + case s.Count != nil: + as := s.Count.As + if as == "" { + as = fmt.Sprintf("%s_count", colName) + } + distinct := "" + if s.Count.Distinct { + distinct = "DISTINCT " + } + req.selectedFields = append( + req.selectedFields, + fmt.Sprintf("COUNT(%s%s) AS %s", distinct, colName, as), + ) + req.whitelistedFields = append(req.whitelistedFields, as) + + case s.Sum != nil: + if s.Sum.As == "" { + return fmt.Errorf("missing 'as' for $sum") + } + + var ( + clause string + params map[string]any + ) + + if s.Sum.Field != "" { + clause = s.Sum.Field + } else { + var err error + clause, params, err = s.Sum.Condition.toSQLWhereClause(ctx, fmt.Sprintf("sel%d", idx), schema, orm.DefaultEncodeConfig) + if err != nil { + return fmt.Errorf("in $sum: %w", err) + } + } + + req.mergeParams(params) + req.selectedFields = append( + req.selectedFields, + fmt.Sprintf("SUM(%s) AS %s", clause, s.Sum.As), + ) + req.whitelistedFields = append(req.whitelistedFields, s.Sum.As) + + case s.Min != nil: + if s.Min.As == "" { + return fmt.Errorf("missing 'as' for $min") + } + + var ( + clause string + params map[string]any + ) + + if s.Min.Field != "" { + clause = field + } else { + var err error + clause, params, err = s.Min.Condition.toSQLWhereClause(ctx, fmt.Sprintf("sel%d", idx), schema, orm.DefaultEncodeConfig) + if err != nil { + return fmt.Errorf("in $min: %w", err) + } + } + + req.mergeParams(params) + req.selectedFields = append( + req.selectedFields, + fmt.Sprintf("MIN(%s) AS %s", clause, s.Min.As), + ) + req.whitelistedFields = append(req.whitelistedFields, s.Min.As) + + case s.Distinct != nil: + req.selectedFields = append(req.selectedFields, fmt.Sprintf("DISTINCT %s", colName)) + req.whitelistedFields = append(req.whitelistedFields, colName) + + default: + req.selectedFields = append(req.selectedFields, colName) + } + } + + return nil +} + +func (req *QueryRequestPayload) mergeParams(params map[string]any) { + if req.paramMap == nil { + req.paramMap = make(map[string]any) + } + + for key, value := range params { + req.paramMap[key] = value + } +} + +func (req *QueryRequestPayload) generateGroupByClause(schema *orm.TableSchema) (string, error) { + if len(req.GroupBy) == 0 { + return "", nil + } + + groupBys := make([]string, len(req.GroupBy)) + for idx, name := range req.GroupBy { + colName, err := req.validateColumnName(schema, name) + if err != nil { + return "", err + } + + groupBys[idx] = colName + } + groupByClause := "GROUP BY " + strings.Join(groupBys, ", ") + + // if there are no explicitly selected fields we default to the + // group-by columns as that's what's expected most of the time anyway... + if len(req.selectedFields) == 0 { + req.selectedFields = append(req.selectedFields, groupBys...) + } + + return groupByClause, nil +} + +func (req *QueryRequestPayload) generateSelectClause() string { + selectClause := "*" + if len(req.selectedFields) > 0 { + selectClause = strings.Join(req.selectedFields, ", ") + } + + return selectClause +} + +func (req *QueryRequestPayload) generateOrderByClause(schema *orm.TableSchema) (string, error) { + if len(req.OrderBy) == 0 { + return "", nil + } + + orderBys := make([]string, len(req.OrderBy)) + for idx, sort := range req.OrderBy { + colName, err := req.validateColumnName(schema, sort.Field) + if err != nil { + return "", err + } + + if sort.Desc { + orderBys[idx] = fmt.Sprintf("%s DESC", colName) + } else { + orderBys[idx] = fmt.Sprintf("%s ASC", colName) + } + } + + return "ORDER BY " + strings.Join(orderBys, ", "), nil +} + +func (req *QueryRequestPayload) validateColumnName(schema *orm.TableSchema, field string) (string, error) { + colDef := schema.GetColumnDef(field) + if colDef != nil { + return colDef.Name, nil + } + + if slices.Contains(req.whitelistedFields, field) { + return field, nil + } + + if slices.Contains(req.selectedFields, field) { + return field, nil + } + + return "", fmt.Errorf("column name %q not allowed", field) +} From 8b4a7330beccfefd2cd536a2a4c6d46592cb56f8 Mon Sep 17 00:00:00 2001 From: Patrick Pacher Date: Thu, 14 Sep 2023 08:42:52 +0200 Subject: [PATCH 07/13] netquery: make parseQueryRequestPayload generic --- netquery/query_handler.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/netquery/query_handler.go b/netquery/query_handler.go index bf2933d5..cb64db4d 100644 --- a/netquery/query_handler.go +++ b/netquery/query_handler.go @@ -25,11 +25,16 @@ type ( IsDevMode func() bool Database *Database } + + BatchQueryHandler struct { + IsDevMode func() bool + Database *Database + } ) func (qh *QueryHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) { start := time.Now() - requestPayload, err := parseQueryRequestPayload(req) + requestPayload, err := parseQueryRequestPayload[QueryRequestPayload](req) if err != nil { http.Error(resp, err.Error(), http.StatusBadRequest) @@ -105,8 +110,11 @@ func (qh *QueryHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) { } } -func parseQueryRequestPayload(req *http.Request) (*QueryRequestPayload, error) { //nolint:dupl - var body io.Reader +func parseQueryRequestPayload[T any](req *http.Request) (*T, error) { //nolint:dupl + var ( + body io.Reader + requestPayload T + ) switch req.Method { case http.MethodPost, http.MethodPut: @@ -117,7 +125,6 @@ func parseQueryRequestPayload(req *http.Request) (*QueryRequestPayload, error) { return nil, fmt.Errorf("invalid HTTP method") } - var requestPayload QueryRequestPayload blob, err := io.ReadAll(body) if err != nil { return nil, fmt.Errorf("failed to read body" + err.Error()) From 2603e42d4e70c5475190277497cd3a37e1bc57c0 Mon Sep 17 00:00:00 2001 From: Patrick Pacher Date: Thu, 14 Sep 2023 08:49:02 +0200 Subject: [PATCH 08/13] netquery: add Server-Timing HTTP header for better SQL query analysis --- go.mod | 3 +++ go.sum | 7 +++++++ netquery/module_api.go | 5 +++-- netquery/query_handler.go | 29 ++++++++++++++++++----------- 4 files changed, 31 insertions(+), 13 deletions(-) diff --git a/go.mod b/go.mod index 5244d774..fbb8ab8f 100644 --- a/go.mod +++ b/go.mod @@ -46,10 +46,12 @@ require ( github.com/danieljoos/wincred v1.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect + github.com/felixge/httpsnoop v1.0.0 // indirect github.com/fxamacker/cbor v1.5.1 // indirect github.com/fxamacker/cbor/v2 v2.5.0 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/gofrs/uuid v4.4.0+incompatible // indirect + github.com/golang/gddo v0.0.0-20180823221919-9d8ff1c67be5 // indirect github.com/google/btree v1.1.2 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/uuid v1.3.1 // indirect @@ -62,6 +64,7 @@ require ( github.com/mdlayher/netlink v1.7.2 // indirect github.com/mdlayher/socket v0.4.1 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-server-timing v1.0.1 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/mr-tron/base58 v1.2.0 // indirect github.com/pkg/errors v0.9.1 // indirect diff --git a/go.sum b/go.sum index b220c683..8c95f327 100644 --- a/go.sum +++ b/go.sum @@ -58,6 +58,8 @@ github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUn github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/felixge/httpsnoop v1.0.0 h1:gh8fMGz0rlOv/1WmRZm7OgncIOTsAj21iNJot48omJQ= +github.com/felixge/httpsnoop v1.0.0/go.mod h1:3+D9sFq0ahK/JeJPhCBUV1xlf4/eIYrUQaxulT0VzX8= github.com/florianl/go-conntrack v0.4.0 h1:TlYkxytdwgVayfU0cKwkHurQA0Rd1ZSEBRckRYDUu18= github.com/florianl/go-conntrack v0.4.0/go.mod h1:iPDx4oIats2T7X7Jm3PFyRCJM1GfZhJaSHOWROYOrE8= github.com/florianl/go-nfqueue v1.3.1 h1:khQ9fYCrjbu5CF8dZF55G2RTIEIQRI0Aj5k3msJR6Gw= @@ -82,6 +84,8 @@ github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRx github.com/gofrs/uuid v4.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/golang/gddo v0.0.0-20180823221919-9d8ff1c67be5 h1:yrv1uUvgXH/tEat+wdvJMRJ4g51GlIydtDpU9pFjaaI= +github.com/golang/gddo v0.0.0-20180823221919-9d8ff1c67be5/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/glog v1.1.1 h1:jxpi2eWoU84wbX9iIEyAeeoac3FLuifZpY9tcNUD9kw= @@ -94,6 +98,7 @@ github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl76 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -183,6 +188,8 @@ github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60 github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-server-timing v1.0.1 h1:f00/aIe8T3MrnLhQHu3tSWvnwc5GV/p5eutuu3hF/tE= +github.com/mitchellh/go-server-timing v1.0.1/go.mod h1:Mo6GKi9FSLwWFAMn3bqVPWe20y5ri5QGQuO9D9MCOxk= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= diff --git a/netquery/module_api.go b/netquery/module_api.go index c51f9a3a..5e182fd1 100644 --- a/netquery/module_api.go +++ b/netquery/module_api.go @@ -7,6 +7,7 @@ import ( "time" "github.com/hashicorp/go-multierror" + servertiming "github.com/mitchellh/go-server-timing" "github.com/safing/portbase/api" "github.com/safing/portbase/config" @@ -93,7 +94,7 @@ func (m *module) prepare() error { Read: api.PermitUser, // Needs read+write as the query is sent using POST data. Write: api.PermitUser, // Needs read+write as the query is sent using POST data. BelongsTo: m.Module, - HandlerFunc: queryHander.ServeHTTP, + HandlerFunc: servertiming.Middleware(queryHander, nil).ServeHTTP, }); err != nil { return fmt.Errorf("failed to register API endpoint: %w", err) } @@ -105,7 +106,7 @@ func (m *module) prepare() error { MimeType: "application/json", Write: api.PermitUser, BelongsTo: m.Module, - HandlerFunc: chartHandler.ServeHTTP, + HandlerFunc: servertiming.Middleware(chartHandler, nil).ServeHTTP, }); err != nil { return fmt.Errorf("failed to register API endpoint: %w", err) } diff --git a/netquery/query_handler.go b/netquery/query_handler.go index cb64db4d..0f6ec725 100644 --- a/netquery/query_handler.go +++ b/netquery/query_handler.go @@ -9,8 +9,8 @@ import ( "net/http" "regexp" "strings" - "time" + servertiming "github.com/mitchellh/go-server-timing" "github.com/safing/portbase/log" "github.com/safing/portmaster/netquery/orm" ) @@ -33,7 +33,12 @@ type ( ) func (qh *QueryHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) { - start := time.Now() + timing := servertiming.FromContext(req.Context()) + + timingQueryParsed := timing.NewMetric("query_parsed"). + WithDesc("Query has been parsed"). + Start() + requestPayload, err := parseQueryRequestPayload[QueryRequestPayload](req) if err != nil { http.Error(resp, err.Error(), http.StatusBadRequest) @@ -41,7 +46,11 @@ func (qh *QueryHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) { return } - queryParsed := time.Since(start) + timingQueryParsed.Stop() + + timingQueryBuilt := timing.NewMetric("query_built"). + WithDesc("The SQL query has been built"). + Start() query, paramMap, err := requestPayload.generateSQL(req.Context(), qh.Database.Schema) if err != nil { @@ -50,7 +59,11 @@ func (qh *QueryHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) { return } - sqlQueryBuilt := time.Since(start) + timingQueryBuilt.Stop() + + timingQueryExecute := timing.NewMetric("sql_exec"). + WithDesc("SQL query execution time"). + Start() // actually execute the query against the database and collect the result var result []map[string]interface{} @@ -65,7 +78,7 @@ func (qh *QueryHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) { return } - sqlQueryFinished := time.Since(start) + timingQueryExecute.Stop() // send the HTTP status code resp.WriteHeader(http.StatusOK) @@ -86,12 +99,6 @@ func (qh *QueryHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) { "orderBy": requestPayload.OrderBy, "groupBy": requestPayload.GroupBy, "selects": requestPayload.Select, - "times": map[string]interface{}{ - "start_time": start, - "query_parsed_after": queryParsed.String(), - "query_built_after": sqlQueryBuilt.String(), - "query_executed_after": sqlQueryFinished.String(), - }, } } else { resultBody = make(map[string]interface{}) From 6e7792f29ec03357019f71d4ed3c7b0e04bead0e Mon Sep 17 00:00:00 2001 From: Patrick Pacher Date: Thu, 14 Sep 2023 09:42:02 +0200 Subject: [PATCH 09/13] netquery: add batch-query handler --- netquery/database.go | 23 ++++++++++ netquery/module_api.go | 18 ++++++++ netquery/query_handler.go | 93 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+) diff --git a/netquery/database.go b/netquery/database.go index aad649ce..ac47197c 100644 --- a/netquery/database.go +++ b/netquery/database.go @@ -57,6 +57,13 @@ type ( writeConn *sqlite.Conn } + BatchExecute struct { + ID string + SQL string + Params map[string]any + Result *[]map[string]any + } + // Conn is a network connection that is stored in a SQLite database and accepted // by the *Database type of this package. This also defines, using the ./orm package, // the table schema and the model that is exposed via the runtime database as well as @@ -325,6 +332,22 @@ func (db *Database) Execute(ctx context.Context, sql string, args ...orm.QueryOp }) } +// ExecuteBatch executes multiple custom SQL query using a read-only connection against the SQLite +// database used by db. +func (db *Database) ExecuteBatch(ctx context.Context, batches []BatchExecute) error { + return db.withConn(ctx, func(conn *sqlite.Conn) error { + merr := new(multierror.Error) + + for _, batch := range batches { + if err := orm.RunQuery(ctx, conn, batch.SQL, orm.WithNamedArgs(batch.Params), orm.WithResult(batch.Result)); err != nil { + merr.Errors = append(merr.Errors, fmt.Errorf("%s: %w", batch.ID, err)) + } + } + + return merr.ErrorOrNil() + }) +} + // CountRows returns the number of rows stored in the database. func (db *Database) CountRows(ctx context.Context) (int, error) { var result []struct { diff --git a/netquery/module_api.go b/netquery/module_api.go index 5e182fd1..39647186 100644 --- a/netquery/module_api.go +++ b/netquery/module_api.go @@ -82,6 +82,11 @@ func (m *module) prepare() error { IsDevMode: config.Concurrent.GetAsBool(config.CfgDevModeKey, false), } + batchHander := &BatchQueryHandler{ + Database: m.Store, + IsDevMode: config.Concurrent.GetAsBool(config.CfgDevModeKey, false), + } + chartHandler := &ChartHandler{ Database: m.Store, } @@ -99,6 +104,19 @@ func (m *module) prepare() error { return fmt.Errorf("failed to register API endpoint: %w", err) } + if err := api.RegisterEndpoint(api.Endpoint{ + Name: "Batch Query Connections", + Description: "Batch query the in-memory sqlite connection database.", + Path: "netquery/query/batch", + MimeType: "application/json", + Read: api.PermitUser, // Needs read+write as the query is sent using POST data. + Write: api.PermitUser, // Needs read+write as the query is sent using POST data. + BelongsTo: m.Module, + HandlerFunc: servertiming.Middleware(batchHander, nil).ServeHTTP, + }); err != nil { + return fmt.Errorf("failed to register API endpoint: %w", err) + } + if err := api.RegisterEndpoint(api.Endpoint{ Name: "Active Connections Chart", Description: "Query the in-memory sqlite connection database and return a chart of active connections.", diff --git a/netquery/query_handler.go b/netquery/query_handler.go index 0f6ec725..ae848a9e 100644 --- a/netquery/query_handler.go +++ b/netquery/query_handler.go @@ -10,6 +10,7 @@ import ( "regexp" "strings" + "github.com/hashicorp/go-multierror" servertiming "github.com/mitchellh/go-server-timing" "github.com/safing/portbase/log" "github.com/safing/portmaster/netquery/orm" @@ -113,6 +114,98 @@ func (qh *QueryHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) { // we can do. log.Errorf("failed to encode JSON response: %s", err) + return + } + +} +func (batch *BatchQueryHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) { + timing := servertiming.FromContext(req.Context()) + + timingQueryParsed := timing.NewMetric("query_parsed"). + WithDesc("Query has been parsed"). + Start() + + requestPayload, err := parseQueryRequestPayload[BatchQueryRequestPayload](req) + if err != nil { + http.Error(resp, err.Error(), http.StatusBadRequest) + + return + } + + timingQueryParsed.Stop() + + response := make(map[string][]map[string]any, len(*requestPayload)) + + batches := make([]BatchExecute, 0, len(*requestPayload)) + + for key, query := range *requestPayload { + + timingQueryBuilt := timing.NewMetric("query_built_" + key). + WithDesc("The SQL query has been built"). + Start() + + sql, paramMap, err := query.generateSQL(req.Context(), batch.Database.Schema) + if err != nil { + http.Error(resp, err.Error(), http.StatusBadRequest) + + return + } + + timingQueryBuilt.Stop() + + var result []map[string]any + batches = append(batches, BatchExecute{ + ID: key, + SQL: sql, + Params: paramMap, + Result: &result, + }) + } + + timingQueryExecute := timing.NewMetric("sql_exec"). + WithDesc("SQL query execution time"). + Start() + + status := http.StatusOK + if err := batch.Database.ExecuteBatch(req.Context(), batches); err != nil { + status = http.StatusInternalServerError + + var merr *multierror.Error + if errors.As(err, &merr) { + for _, e := range merr.Errors { + resp.Header().Add("X-Query-Error", e.Error()) + } + } else { + // Should not happen, ExecuteBatch always returns a multierror.Error + resp.WriteHeader(status) + + return + } + } + + timingQueryExecute.Stop() + + // collect the results + for _, b := range batches { + response[b.ID] = *b.Result + } + + // send the HTTP status code + resp.WriteHeader(status) + + // prepare the result encoder. + enc := json.NewEncoder(resp) + enc.SetEscapeHTML(false) + enc.SetIndent("", " ") + + // and finally stream the response + if err := enc.Encode(response); err != nil { + // we failed to encode the JSON body to resp so we likely either already sent a + // few bytes or the pipe was already closed. In either case, trying to send the + // error using http.Error() is non-sense. We just log it out here and that's all + // we can do. + log.Errorf("failed to encode JSON response: %s", err) + return } } From 844a19bc38ac1b8ea4f11e2563294e41c7fc33f6 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 14 Sep 2023 15:30:25 +0200 Subject: [PATCH 10/13] Detect system locale and estimate best default locale setting --- core/config.go | 54 ++++++++++++++++++++++++++++++++++++++++++-------- go.mod | 2 ++ go.sum | 10 ++++++++++ 3 files changed, 58 insertions(+), 8 deletions(-) diff --git a/core/config.go b/core/config.go index 7a549409..28fb2484 100644 --- a/core/config.go +++ b/core/config.go @@ -3,7 +3,11 @@ package core import ( "flag" + locale "github.com/Xuanwo/go-locale" + "golang.org/x/exp/slices" + "github.com/safing/portbase/config" + "github.com/safing/portbase/log" ) // Configuration Keys. @@ -14,7 +18,7 @@ var ( CfgNetworkServiceKey = "core/networkService" defaultNetworkServiceMode bool - CfgLocaleKey = "core/localeID" + CfgLocaleKey = "core/locale" ) func init() { @@ -44,21 +48,21 @@ func registerConfig() error { } if err := config.Register(&config.Option{ - Name: "Locale", + Name: "Time and Date Format", Key: CfgLocaleKey, - Description: "Configures the locale for the user interface. This mainly affects rendering of dates, currency and numbers. Note that the Portmaster does not yet support different languages.", + Description: "Configures the time and date format for the user interface. Selection is an example and correct formatting in the UI is a continual work in progress.", OptType: config.OptTypeString, ExpertiseLevel: config.ExpertiseLevelUser, ReleaseLevel: config.ReleaseLevelStable, - DefaultValue: "en-GB", + DefaultValue: getDefaultLocale(), PossibleValues: []config.PossibleValue{ { - Name: "en-GB", - Value: "en-GB", + Name: "24h DD-MM-YYYY", + Value: enGBLocale, }, { - Name: "en-US", - Value: "en-US", + Name: "12h MM/DD/YYYY", + Value: enUSLocale, }, }, Annotations: config.Annotations{ @@ -72,3 +76,37 @@ func registerConfig() error { return nil } + +func getDefaultLocale() string { + // Get locales from system. + detectedLocales, err := locale.DetectAll() + if err != nil { + log.Warningf("core: failed to detect locale: %s", err) + return enGBLocale + } + + // log.Debugf("core: detected locales: %s", detectedLocales) + + // Check if there is a locale that corresponds to the en-US locale. + for _, detectedLocale := range detectedLocales { + if slices.Contains[[]string, string](defaultEnUSLocales, detectedLocale.String()) { + return enUSLocale + } + } + + // Otherwise, return the en-GB locale as default. + return enGBLocale +} + +var ( + enGBLocale = "en-GB" + enUSLocale = "en-US" + + defaultEnUSLocales = []string{ + "en-AS", // English (American Samoa) + "en-GU", // English (Guam) + "en-UM", // English (U.S. Minor Outlying Islands) + "en-US", // English (United States) + "en-VI", // English (U.S. Virgin Islands) + } +) diff --git a/go.mod b/go.mod index fbb8ab8f..3c2e1c02 100644 --- a/go.mod +++ b/go.mod @@ -37,6 +37,7 @@ require ( require ( github.com/VictoriaMetrics/metrics v1.24.0 // indirect + github.com/Xuanwo/go-locale v1.1.0 // indirect github.com/aead/ecdh v0.2.0 // indirect github.com/aead/serpent v0.0.0-20160714141033-fba169763ea6 // indirect github.com/alessio/shellescape v1.4.2 // indirect @@ -91,6 +92,7 @@ require ( go.etcd.io/bbolt v1.3.7 // indirect golang.org/x/crypto v0.12.0 // indirect golang.org/x/mod v0.12.0 // indirect + golang.org/x/text v0.12.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 8c95f327..7ba1c7ed 100644 --- a/go.sum +++ b/go.sum @@ -8,6 +8,8 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE github.com/VictoriaMetrics/metrics v1.22.2/go.mod h1:rAr/llLpEnAdTehiNlUxKgnjcOuROSzpw0GvjpEbvFc= github.com/VictoriaMetrics/metrics v1.24.0 h1:ILavebReOjYctAGY5QU2F9X0MYvkcrG3aEn2RKa1Zkw= github.com/VictoriaMetrics/metrics v1.24.0/go.mod h1:eFT25kvsTidQFHb6U0oa0rTrDRdz4xTYjpL8+UPohys= +github.com/Xuanwo/go-locale v1.1.0 h1:51gUxhxl66oXAjI9uPGb2O0qwPECpriKQb2hl35mQkg= +github.com/Xuanwo/go-locale v1.1.0/go.mod h1:UKrHoZB3FPIk9wIG2/tVSobnHgNnceGSH3Y8DY5cASs= github.com/aead/ecdh v0.2.0 h1:pYop54xVaq/CEREFEcukHRZfTdjiWvYIsZDXXrBapQQ= github.com/aead/ecdh v0.2.0/go.mod h1:a9HHtXuSo8J1Js1MwLQx2mBhkXMT6YwUmVVEY4tTB8U= github.com/aead/serpent v0.0.0-20160714141033-fba169763ea6 h1:5L8Mj9Co9sJVgW3TpYk2gxGJnDjsYuboNTcRmbtGKGs= @@ -112,6 +114,7 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaU github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= @@ -144,6 +147,7 @@ github.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXp github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U= github.com/jsimonetti/rtnetlink v0.0.0-20210525051524-4cc836578190/go.mod h1:NmKSdU4VGSiv1bMsdqNALI4RSvvjtz65tTMCnD05qLo= github.com/jsimonetti/rtnetlink v0.0.0-20211022192332-93da33804786/go.mod h1:v4hqbTdfQngbVSZJVWUhGE/lbTFf9jb+ygmNUDQMuOs= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -233,6 +237,8 @@ github.com/seehuhn/sha256d v1.0.0 h1:TXTsAuEWr02QjRm153Fnvvb6fXXDo7Bmy1FizxarGYw github.com/seehuhn/sha256d v1.0.0/go.mod h1:PEuxg9faClSveVuFXacQmi+NtDI/PX8bpKjtNzf2+s4= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.7/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= @@ -389,6 +395,7 @@ golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211023085530-d6a326fbbf70/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -413,9 +420,12 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= From 8f08e962dafc771519d70cc131510034739b09f5 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 14 Sep 2023 15:37:55 +0200 Subject: [PATCH 11/13] Update to portbase v0.17.4 --- go.mod | 16 ++++++++-------- go.sum | 11 +++++++++++ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 3c2e1c02..37d2efad 100644 --- a/go.mod +++ b/go.mod @@ -18,8 +18,8 @@ require ( github.com/miekg/dns v1.1.55 github.com/oschwald/maxminddb-golang v1.12.0 github.com/safing/jess v0.3.1 - github.com/safing/portbase v0.17.3 - github.com/safing/portmaster-android/go v0.0.0-20230605085256-6abf4c495626 + github.com/safing/portbase v0.17.4 + github.com/safing/portmaster-android/go v0.0.0-20230830120134-3226ceac3bec github.com/safing/spn v0.6.18-prep github.com/shirou/gopsutil v3.21.11+incompatible github.com/spf13/cobra v1.7.0 @@ -28,10 +28,10 @@ require ( github.com/tannerryan/ring v1.1.2 github.com/tevino/abool v1.2.0 github.com/umahmood/haversine v0.0.0-20151105152445-808ab04add26 - golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 - golang.org/x/net v0.14.0 + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 + golang.org/x/net v0.15.0 golang.org/x/sync v0.3.0 - golang.org/x/sys v0.11.0 + golang.org/x/sys v0.12.0 zombiezen.com/go/sqlite v0.13.1 ) @@ -90,11 +90,11 @@ require ( github.com/yusufpapurcu/wmi v1.2.3 // indirect github.com/zalando/go-keyring v0.2.3 // indirect go.etcd.io/bbolt v1.3.7 // indirect - golang.org/x/crypto v0.12.0 // indirect + golang.org/x/crypto v0.13.0 // indirect golang.org/x/mod v0.12.0 // indirect - golang.org/x/text v0.12.0 // indirect + golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 // indirect + golang.org/x/tools v0.13.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gvisor.dev/gvisor v0.0.0-20220817001344-846276b3dbc5 // indirect diff --git a/go.sum b/go.sum index 7ba1c7ed..287c0537 100644 --- a/go.sum +++ b/go.sum @@ -223,8 +223,12 @@ github.com/safing/portbase v0.17.2 h1:HzJkURMmXkv30wMHB7xJ+Z5U5aTMe+EzvlHavKoKko github.com/safing/portbase v0.17.2/go.mod h1:1cVgDZIsPiqM5b+K88Kshir5PGIvsftYkx7y1x925+8= github.com/safing/portbase v0.17.3 h1:LLV2kq4mli2phHFHxigTkIoOjConieMTWsDyi9kJd00= github.com/safing/portbase v0.17.3/go.mod h1:1cVgDZIsPiqM5b+K88Kshir5PGIvsftYkx7y1x925+8= +github.com/safing/portbase v0.17.4 h1:4RhItvFujwdfLQVfwvB+VYER33AT//Ywv317Vj01TEQ= +github.com/safing/portbase v0.17.4/go.mod h1:suLPSjOTqA7iDLozis5OI7PSw+wqJNT8SLvdBhRPlqI= github.com/safing/portmaster-android/go v0.0.0-20230605085256-6abf4c495626 h1:olc/REnUdpJN/Gmz8B030OxLpMYxyPDTrDILNEw0eKs= github.com/safing/portmaster-android/go v0.0.0-20230605085256-6abf4c495626/go.mod h1:abwyAQrZGemWbSh/aCD9nnkp0SvFFf/mGWkAbOwPnFE= +github.com/safing/portmaster-android/go v0.0.0-20230830120134-3226ceac3bec h1:oSJY1seobofPwpMoJRkCgXnTwfiQWNfGMCPDfqgAEfg= +github.com/safing/portmaster-android/go v0.0.0-20230830120134-3226ceac3bec/go.mod h1:abwyAQrZGemWbSh/aCD9nnkp0SvFFf/mGWkAbOwPnFE= github.com/safing/spn v0.6.17 h1:3Lu1cpTcy8zYhA/2UEfeG08Rx1nlwIj1aobSfNXXgUI= github.com/safing/spn v0.6.17/go.mod h1:2CuZfJJazIYyMDrhiwX2eFal0urQyLiX8rXLvJiCTcw= github.com/safing/spn v0.6.18-prep h1:e6jjDFVsOh9B7YQLCjfCgqbCHiHOxRdpjXi5gR+85rA= @@ -325,8 +329,10 @@ golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.0.0-20221010152910-d6f0a8c073c2/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ= golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -358,6 +364,7 @@ golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220927171203-f486391704dc/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -412,6 +419,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -422,6 +431,7 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -432,6 +442,7 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E= golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From 25ffffecf92d53c58e5b030e0ca3b7d62be21569 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 14 Sep 2023 15:41:47 +0200 Subject: [PATCH 12/13] Update deps --- go.mod | 14 +++++------ go.sum | 79 +++++++++++++++++++++++++++++++++++++--------------------- 2 files changed, 58 insertions(+), 35 deletions(-) diff --git a/go.mod b/go.mod index 37d2efad..6135b026 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/safing/portmaster go 1.20 require ( + github.com/Xuanwo/go-locale v1.1.0 github.com/agext/levenshtein v1.2.3 github.com/cilium/ebpf v0.11.0 github.com/coreos/go-iptables v0.7.0 @@ -15,12 +16,13 @@ require ( github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-version v1.6.0 github.com/jackc/puddle/v2 v2.2.1 - github.com/miekg/dns v1.1.55 + github.com/miekg/dns v1.1.56 + github.com/mitchellh/go-server-timing v1.0.1 github.com/oschwald/maxminddb-golang v1.12.0 github.com/safing/jess v0.3.1 github.com/safing/portbase v0.17.4 github.com/safing/portmaster-android/go v0.0.0-20230830120134-3226ceac3bec - github.com/safing/spn v0.6.18-prep + github.com/safing/spn v0.6.19 github.com/shirou/gopsutil v3.21.11+incompatible github.com/spf13/cobra v1.7.0 github.com/spkg/zipfs v0.7.1 @@ -37,7 +39,6 @@ require ( require ( github.com/VictoriaMetrics/metrics v1.24.0 // indirect - github.com/Xuanwo/go-locale v1.1.0 // indirect github.com/aead/ecdh v0.2.0 // indirect github.com/aead/serpent v0.0.0-20160714141033-fba169763ea6 // indirect github.com/alessio/shellescape v1.4.2 // indirect @@ -47,12 +48,12 @@ require ( github.com/danieljoos/wincred v1.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/felixge/httpsnoop v1.0.0 // indirect + github.com/felixge/httpsnoop v1.0.3 // indirect github.com/fxamacker/cbor v1.5.1 // indirect github.com/fxamacker/cbor/v2 v2.5.0 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/gofrs/uuid v4.4.0+incompatible // indirect - github.com/golang/gddo v0.0.0-20180823221919-9d8ff1c67be5 // indirect + github.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f // indirect github.com/google/btree v1.1.2 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/uuid v1.3.1 // indirect @@ -63,9 +64,8 @@ require ( github.com/josharian/native v1.1.0 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/mdlayher/netlink v1.7.2 // indirect - github.com/mdlayher/socket v0.4.1 // indirect + github.com/mdlayher/socket v0.5.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect - github.com/mitchellh/go-server-timing v1.0.1 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/mr-tron/base58 v1.2.0 // indirect github.com/pkg/errors v0.9.1 // indirect diff --git a/go.sum b/go.sum index 287c0537..776f1138 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +cloud.google.com/go v0.16.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/AlecAivazis/survey/v2 v2.3.6/go.mod h1:4AuI9b7RjAR+G7v9+C4YSlX/YL3K3cWNXgWXOhllqvI= github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M= github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= @@ -26,6 +27,7 @@ github.com/awalterschulze/gographviz v2.0.3+incompatible h1:9sVEXJBJLwGX7EQVhLm2 github.com/awalterschulze/gographviz v2.0.3+incompatible/go.mod h1:GEV5wmg4YquNw7v1kkyoX9etIk8yVmXj+AkDHuuETHs= github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw= github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0= +github.com/bradfitz/gomemcache v0.0.0-20170208213004-1952afaa557d/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60= github.com/brianvoe/gofakeit v3.18.0+incompatible h1:wDOmHc9DLG4nRjUVVaxA+CEglKOW72Y5+4WNxUIkjM8= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= @@ -60,25 +62,29 @@ github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUn github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/felixge/httpsnoop v1.0.0 h1:gh8fMGz0rlOv/1WmRZm7OgncIOTsAj21iNJot48omJQ= github.com/felixge/httpsnoop v1.0.0/go.mod h1:3+D9sFq0ahK/JeJPhCBUV1xlf4/eIYrUQaxulT0VzX8= +github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= +github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/florianl/go-conntrack v0.4.0 h1:TlYkxytdwgVayfU0cKwkHurQA0Rd1ZSEBRckRYDUu18= github.com/florianl/go-conntrack v0.4.0/go.mod h1:iPDx4oIats2T7X7Jm3PFyRCJM1GfZhJaSHOWROYOrE8= github.com/florianl/go-nfqueue v1.3.1 h1:khQ9fYCrjbu5CF8dZF55G2RTIEIQRI0Aj5k3msJR6Gw= github.com/florianl/go-nfqueue v1.3.1/go.mod h1:aHWbgkhryJxF5XxYvJ3oRZpdD4JP74Zu/hP1zuhja+M= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA= +github.com/fsnotify/fsnotify v1.4.3-0.20170329110642-4da3e2cfbabc/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fxamacker/cbor v1.5.1 h1:XjQWBgdmQyqimslUh5r4tUGmoqzHmBFQOImkWGi2awg= github.com/fxamacker/cbor v1.5.1/go.mod h1:3aPGItF174ni7dDzd6JZ206H8cmr4GDNBGpPa971zsU= github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/fxamacker/cbor/v2 v2.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADivE= github.com/fxamacker/cbor/v2 v2.5.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= +github.com/garyburd/redigo v1.1.1-0.20170914051019-70e1b1943d4f/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/go-stack/stack v1.6.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -86,17 +92,21 @@ github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRx github.com/gofrs/uuid v4.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/golang/gddo v0.0.0-20180823221919-9d8ff1c67be5 h1:yrv1uUvgXH/tEat+wdvJMRJ4g51GlIydtDpU9pFjaaI= github.com/golang/gddo v0.0.0-20180823221919-9d8ff1c67be5/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4= +github.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f h1:16RtHeWGkJMc80Etb8RPCcKevXGldr57+LOyZt8zOlg= +github.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f/go.mod h1:ijRvpgDJDI262hYq/IQVYgf8hd8IHUs93Ol0kvMBAx4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= -github.com/golang/glog v1.1.1 h1:jxpi2eWoU84wbX9iIEyAeeoac3FLuifZpY9tcNUD9kw= +github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= +github.com/golang/lint v0.0.0-20170918230701-e5d664eb928e/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/go-cmp v0.1.1-0.20171103154506-982329095285/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -114,11 +124,14 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaU github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20170920190843-316c5e0ff04e/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -126,8 +139,10 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/hcl v0.0.0-20170914154624-68e816d1c783/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68= +github.com/inconshreveable/log15 v0.0.0-20170622235902-74a0988b5f80/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= @@ -147,6 +162,7 @@ github.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXp github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U= github.com/jsimonetti/rtnetlink v0.0.0-20210525051524-4cc836578190/go.mod h1:NmKSdU4VGSiv1bMsdqNALI4RSvvjtz65tTMCnD05qLo= github.com/jsimonetti/rtnetlink v0.0.0-20211022192332-93da33804786/go.mod h1:v4hqbTdfQngbVSZJVWUhGE/lbTFf9jb+ygmNUDQMuOs= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -155,9 +171,12 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/magiconair/properties v1.7.4-0.20170902060319-8d7837e64d3c/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mattn/go-colorable v0.0.10-0.20170816031813-ad5389df28cd/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.2/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= @@ -183,17 +202,18 @@ github.com/mdlayher/socket v0.0.0-20210307095302-262dc9984e00/go.mod h1:GAFlyu4/ github.com/mdlayher/socket v0.0.0-20211007213009-516dcbdf0267/go.mod h1:nFZ1EtZYK8Gi/k6QNu7z7CgO20i/4ExeQswwWuPmG/g= github.com/mdlayher/socket v0.1.0/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs= github.com/mdlayher/socket v0.1.1/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs= -github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= -github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= +github.com/mdlayher/socket v0.5.0 h1:ilICZmJcQz70vrWVes1MFera4jGiWNocSkykwwoy3XI= +github.com/mdlayher/socket v0.5.0/go.mod h1:WkcBFfvyG8QENs5+hfQPl1X6Jpd2yeLIYgrGFmJiJxI= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= -github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= -github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE= +github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-server-timing v1.0.1 h1:f00/aIe8T3MrnLhQHu3tSWvnwc5GV/p5eutuu3hF/tE= github.com/mitchellh/go-server-timing v1.0.1/go.mod h1:Mo6GKi9FSLwWFAMn3bqVPWe20y5ri5QGQuO9D9MCOxk= +github.com/mitchellh/mapstructure v0.0.0-20170523030023-d0303fe80992/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= @@ -201,6 +221,7 @@ github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs= github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY= +github.com/pelletier/go-toml v1.0.1-0.20170904195809-1d6b12b7cb29/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -219,20 +240,12 @@ github.com/safing/jess v0.3.1 h1:cMZVhi2whW/YdD98MPLeLIWJndQ7o2QVt2HefQ/ByFA= github.com/safing/jess v0.3.1/go.mod h1:aj73Eot1zm2ETkJuw9hJlIO8bRom52uBbsCHemvlZmA= github.com/safing/portbase v0.15.2/go.mod h1:5bHi99fz7Hh/wOsZUOI631WF9ePSHk57c4fdlOMS91Y= github.com/safing/portbase v0.16.2/go.mod h1:mzNCWqPbO7vIYbbK5PElGbudwd2vx4YPNawymL8Aro8= -github.com/safing/portbase v0.17.2 h1:HzJkURMmXkv30wMHB7xJ+Z5U5aTMe+EzvlHavKoKkos= -github.com/safing/portbase v0.17.2/go.mod h1:1cVgDZIsPiqM5b+K88Kshir5PGIvsftYkx7y1x925+8= -github.com/safing/portbase v0.17.3 h1:LLV2kq4mli2phHFHxigTkIoOjConieMTWsDyi9kJd00= -github.com/safing/portbase v0.17.3/go.mod h1:1cVgDZIsPiqM5b+K88Kshir5PGIvsftYkx7y1x925+8= github.com/safing/portbase v0.17.4 h1:4RhItvFujwdfLQVfwvB+VYER33AT//Ywv317Vj01TEQ= github.com/safing/portbase v0.17.4/go.mod h1:suLPSjOTqA7iDLozis5OI7PSw+wqJNT8SLvdBhRPlqI= -github.com/safing/portmaster-android/go v0.0.0-20230605085256-6abf4c495626 h1:olc/REnUdpJN/Gmz8B030OxLpMYxyPDTrDILNEw0eKs= -github.com/safing/portmaster-android/go v0.0.0-20230605085256-6abf4c495626/go.mod h1:abwyAQrZGemWbSh/aCD9nnkp0SvFFf/mGWkAbOwPnFE= github.com/safing/portmaster-android/go v0.0.0-20230830120134-3226ceac3bec h1:oSJY1seobofPwpMoJRkCgXnTwfiQWNfGMCPDfqgAEfg= github.com/safing/portmaster-android/go v0.0.0-20230830120134-3226ceac3bec/go.mod h1:abwyAQrZGemWbSh/aCD9nnkp0SvFFf/mGWkAbOwPnFE= -github.com/safing/spn v0.6.17 h1:3Lu1cpTcy8zYhA/2UEfeG08Rx1nlwIj1aobSfNXXgUI= -github.com/safing/spn v0.6.17/go.mod h1:2CuZfJJazIYyMDrhiwX2eFal0urQyLiX8rXLvJiCTcw= -github.com/safing/spn v0.6.18-prep h1:e6jjDFVsOh9B7YQLCjfCgqbCHiHOxRdpjXi5gR+85rA= -github.com/safing/spn v0.6.18-prep/go.mod h1:flegLqCJjFQ0uDB39GMWrIttJga5cSeNea2G6XlKRJ0= +github.com/safing/spn v0.6.19 h1:z4i8hb5FGKjmgSzA4MzJ8mOc0hYp11zgXzujrHwwV5k= +github.com/safing/spn v0.6.19/go.mod h1:LRWLManSXHTViiDqU2qNy3w07auMuadOnVW8wAB/Cgw= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/seehuhn/fortuna v1.0.1 h1:lu9+CHsmR0bZnx5Ay646XvCSRJ8PJTi5UYJwDBX68H0= @@ -241,20 +254,27 @@ github.com/seehuhn/sha256d v1.0.0 h1:TXTsAuEWr02QjRm153Fnvvb6fXXDo7Bmy1FizxarGYw github.com/seehuhn/sha256d v1.0.0/go.mod h1:PEuxg9faClSveVuFXacQmi+NtDI/PX8bpKjtNzf2+s4= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.7 h1:I6tZjLXD2Q1kjvNbIzB1wvQBsXmKXiVrhpRE8ZjP5jY= github.com/smartystreets/goconvey v1.6.7/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v0.0.0-20170901052352-ee1bd8ee15a1/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.1.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/jwalterweatherman v0.0.0-20170901151539-12bd96e66386/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.1-0.20170901120850-7aff26db30c1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spkg/zipfs v0.7.1 h1:+2X5lvNHTybnDMQZAIHgedRXZK1WXdc+94R/P5v2XWE= github.com/spkg/zipfs v0.7.1/go.mod h1:48LW+/Rh1G7aAav1ew1PdlYn52T+LM+ARmSHfDNJvg8= @@ -327,11 +347,9 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20221010152910-d6f0a8c073c2/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ= -golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= @@ -342,6 +360,7 @@ golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -362,9 +381,10 @@ golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220107192237-5cfca573fb4d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220927171203-f486391704dc/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/oauth2 v0.0.0-20170912212905-13449ad91cb2/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20170517211232-f52d1811a629/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -417,7 +437,6 @@ golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -426,12 +445,13 @@ golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220919170432-7a66f970e087/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/time v0.0.0-20170424234030-8be79e1e0910/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -440,13 +460,16 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E= -golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= +golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.0.0-20170921000349-586095a6e407/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20170918111702-1e559d0a00ee/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/grpc v1.2.1-0.20170921194603-d4b75ebd4f9f/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= From c5bca9c8a2a25160d43f550fa6e223d1db161e8f Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 14 Sep 2023 15:58:32 +0200 Subject: [PATCH 13/13] Fix linter warnings --- netquery/database.go | 1 + netquery/orm/decoder.go | 1 + netquery/orm/encoder.go | 2 +- netquery/query.go | 4 ++-- netquery/query_handler.go | 5 ++++- netquery/query_request.go | 4 +++- resolver/resolver_test.go | 2 +- 7 files changed, 13 insertions(+), 6 deletions(-) diff --git a/netquery/database.go b/netquery/database.go index ac47197c..807c0097 100644 --- a/netquery/database.go +++ b/netquery/database.go @@ -57,6 +57,7 @@ type ( writeConn *sqlite.Conn } + // BatchExecute executes multiple queries in one transaction. BatchExecute struct { ID string SQL string diff --git a/netquery/orm/decoder.go b/netquery/orm/decoder.go index 5b87df82..21ce6146 100644 --- a/netquery/orm/decoder.go +++ b/netquery/orm/decoder.go @@ -461,6 +461,7 @@ func getKind(val reflect.Value) reflect.Kind { return NormalizeKind(kind) } +// NormalizeKind returns a normalized kind of the given kind. func NormalizeKind(kind reflect.Kind) reflect.Kind { switch { case kind >= reflect.Int && kind <= reflect.Int64: diff --git a/netquery/orm/encoder.go b/netquery/orm/encoder.go index 107f9f77..6dcd0e68 100644 --- a/netquery/orm/encoder.go +++ b/netquery/orm/encoder.go @@ -183,7 +183,7 @@ func DatetimeEncoder(loc *time.Location) EncodeFunc { case (normalizedKind == reflect.Int || normalizedKind == reflect.Uint || normalizedKind == reflect.Float64) && colDef.IsTime: seconds := int64(0) - switch normalizedKind { + switch normalizedKind { //nolint:exhaustive // Previous switch case assures these types. case reflect.Int: seconds = val.Int() case reflect.Uint: diff --git a/netquery/query.go b/netquery/query.go index a4502849..804f85fb 100644 --- a/netquery/query.go +++ b/netquery/query.go @@ -311,7 +311,7 @@ func (match Matcher) toSQLConditionClause(ctx context.Context, suffix string, co for idx, value := range values { var ( - encodedValue any = value + encodedValue any err error ) @@ -344,7 +344,7 @@ func (match Matcher) toSQLConditionClause(ctx context.Context, suffix string, co // NOTE(ppacher): for now we assume that the type of each element of values // is the same. We also can be sure that there is always at least one value. // - // FIXME(ppacher): if we start supporting values of different types here + // TODO(ppacher): if we start supporting values of different types here // we need to revisit the whole behavior as we might need to do more boolean // expression nesting to support that. kind := orm.NormalizeKind(reflect.TypeOf(values[0]).Kind()) diff --git a/netquery/query_handler.go b/netquery/query_handler.go index ae848a9e..8e704d3e 100644 --- a/netquery/query_handler.go +++ b/netquery/query_handler.go @@ -12,6 +12,7 @@ import ( "github.com/hashicorp/go-multierror" servertiming "github.com/mitchellh/go-server-timing" + "github.com/safing/portbase/log" "github.com/safing/portmaster/netquery/orm" ) @@ -27,6 +28,8 @@ type ( Database *Database } + // BatchQueryHandler implements http.Handler and allows to perform SQL + // query and aggregate functions on Database in batches. BatchQueryHandler struct { IsDevMode func() bool Database *Database @@ -116,8 +119,8 @@ func (qh *QueryHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) { return } - } + func (batch *BatchQueryHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) { timing := servertiming.FromContext(req.Context()) diff --git a/netquery/query_request.go b/netquery/query_request.go index e294d6ea..b4a07041 100644 --- a/netquery/query_request.go +++ b/netquery/query_request.go @@ -5,11 +5,13 @@ import ( "fmt" "strings" - "github.com/safing/portmaster/netquery/orm" "golang.org/x/exp/slices" + + "github.com/safing/portmaster/netquery/orm" ) type ( + // QueryRequestPayload describes the payload of a netquery query. QueryRequestPayload struct { Select Selects `json:"select"` Query Query `json:"query"` diff --git a/resolver/resolver_test.go b/resolver/resolver_test.go index a03b3eb9..397a914c 100644 --- a/resolver/resolver_test.go +++ b/resolver/resolver_test.go @@ -119,7 +119,7 @@ func TestPublicSuffix(t *testing.T) { testSuffix(t, "golang.dev.", "golang.dev.", true) testSuffix(t, "golang.net.", "golang.net.", true) testSuffix(t, "play.golang.org.", "golang.org.", true) - testSuffix(t, "gophers.in.space.museum.", "in.space.museum.", true) + testSuffix(t, "gophers.in.space.museum.", "space.museum.", true) testSuffix(t, "0emm.com.", "0emm.com.", true) testSuffix(t, "a.0emm.com.", "", true) testSuffix(t, "b.c.d.0emm.com.", "c.d.0emm.com.", true)