Skip to content
Snippets Groups Projects
Commit c618256d authored by Johan de Klerk's avatar Johan de Klerk
Browse files

Merge branch 'main' of gitlab.bob.co.za:bob-public-utils/bobgroup-go-utils

parents 8a38bdd5 63832183
Branches
Tags
No related merge requests found
...@@ -15,7 +15,7 @@ import ( ...@@ -15,7 +15,7 @@ import (
"github.com/aws/aws-lambda-go/lambdacontext" "github.com/aws/aws-lambda-go/lambdacontext"
) )
const HTTPXRequestIDHeaderValue = "X-Request-ID" const HTTPXRequestIDHeaderKey = "X-Request-ID"
func RequestIDFromLambdaContext(ctx context.Context) *string { func RequestIDFromLambdaContext(ctx context.Context) *string {
// Get request ID from context // Get request ID from context
...@@ -39,14 +39,14 @@ func RequestIDFromHeaders(headers map[string]string, requestIDHeaderKey string) ...@@ -39,14 +39,14 @@ func RequestIDFromHeaders(headers map[string]string, requestIDHeaderKey string)
func AddRequestIDToHeaders(requestID *string, responseHeaders map[string]string, requestIDHeaderKey string, requestHeaders map[string]string) { func AddRequestIDToHeaders(requestID *string, responseHeaders map[string]string, requestIDHeaderKey string, requestHeaders map[string]string) {
if requestID != nil && responseHeaders != nil { if requestID != nil && responseHeaders != nil {
responseHeaders[requestIDHeaderKey] = *requestID responseHeaders[requestIDHeaderKey] = *requestID
responseHeaders[HTTPXRequestIDHeaderValue] = *requestID responseHeaders[HTTPXRequestIDHeaderKey] = *requestID
} }
// Add the HTTP X-Request-ID request header to the response headers: https://http.dev/x-request-id // Add the HTTP X-Request-ID request header to the response headers: https://http.dev/x-request-id
for key, val := range requestHeaders { for key, val := range requestHeaders {
// Don't be case-sensitive // Don't be case-sensitive
if strings.ToLower(key) == strings.ToLower(HTTPXRequestIDHeaderValue) { if strings.ToLower(key) == strings.ToLower(HTTPXRequestIDHeaderKey) {
responseHeaders[key] = val responseHeaders[HTTPXRequestIDHeaderKey] = val
break break
} }
} }
......
...@@ -31,6 +31,7 @@ var ignoredTableInserts = []string{ ...@@ -31,6 +31,7 @@ var ignoredTableInserts = []string{
} }
type QueryHook struct { type QueryHook struct {
IgnoredTableInserts []string
Debug bool Debug bool
} }
...@@ -47,8 +48,9 @@ func (d QueryHook) AfterQuery(_ context.Context, event *bun.QueryEvent) { ...@@ -47,8 +48,9 @@ func (d QueryHook) AfterQuery(_ context.Context, event *bun.QueryEvent) {
shouldLogQuery := !strings.Contains(sqlQuery, "api_key") shouldLogQuery := !strings.Contains(sqlQuery, "api_key")
// Don't log queries for certain tables // Don't log queries for certain tables
ignoredTableInsertsCombined := append(ignoredTableInserts, d.IgnoredTableInserts...)
tableName := TableNameForQuery(event) tableName := TableNameForQuery(event)
if lo.Contains(ignoredTableInserts, tableName) { if lo.Contains(ignoredTableInsertsCombined, tableName) {
shouldLogQuery = false shouldLogQuery = false
} }
......
...@@ -30,33 +30,32 @@ var build string ...@@ -30,33 +30,32 @@ var build string
var raygunClient *raygun4go.Client var raygunClient *raygun4go.Client
// Password filtering // Password filtering
var passwordRegex = regexp.MustCompile(`(?i:\\?"password\\?"\s*:\s*\\?"(.*)\\?",).*`) var passwordRegex = regexp.MustCompile(`(?i:\\?"password\\?"\s*:\s*\\?"(.*)\\?").*`)
var byteArrayRegex = regexp.MustCompile(`(?i:\\?"(?i:[\w]*)(?i:byte|data)(?i:[\w]*)\\?"\s*:\s*\[([\d\s,]+)*\])`)
func SanitiseLogs(logString string) string { func SanitiseLogs(logString string) string {
var isValidJsonString bool
isValidJsonString, logString = string_utils.PrettyJSON(logString)
if !isValidJsonString {
return logString
}
logString = MaskByteArraysInJsonString(logString)
logString = MaskPasswordsInJsonString(logString) logString = MaskPasswordsInJsonString(logString)
return logString return logString
} }
// MaskPasswordsInJsonString takes a string and, if it is a JSON string, sanitises all the password. In order for the // MaskPasswordsInJsonString takes a string and sanitises all the instances of fields named password.
// regex to work correctly we need to prettify the JSON, so the function always returns a formatted JSON string. // E.g. "{"password": "xyz123"}" will become "{"password": "***"}"
func MaskPasswordsInJsonString(jsonString string) string { func MaskPasswordsInJsonString(jsonString string) string {
var isValidJsonString bool return string_utils.ReplaceAllRegexStringSubmatch(passwordRegex, jsonString, "***")
isValidJsonString, jsonString = string_utils.PrettyJSON(jsonString)
if !isValidJsonString {
return jsonString
}
if passwordRegex.MatchString(jsonString) {
result := passwordRegex.FindAllStringSubmatch(jsonString, -1)
for _, match := range result {
if len(match) > 1 {
jsonString = strings.ReplaceAll(jsonString, match[1], "***")
}
}
} }
return jsonString // MaskByteArraysInJsonString takes a string and truncates all the instances of number array fields have the word
// "byte" in the name. E.g. {"file_bytes": [123,68,103]} will become "{"file_bytes": [...]}"
func MaskByteArraysInJsonString(jsonString string) string {
return string_utils.ReplaceAllRegexStringSubmatch(byteArrayRegex, jsonString, "...")
} }
func SanitiseFields(fields map[string]interface{}) map[string]interface{} { func SanitiseFields(fields map[string]interface{}) map[string]interface{} {
......
...@@ -16,7 +16,14 @@ import ( ...@@ -16,7 +16,14 @@ import (
"golang.org/x/text/unicode/norm" "golang.org/x/text/unicode/norm"
) )
const snakeCasePattern = `[a-z]([a-z0-9_]*[a-z0-9])*` const (
snakeCasePattern = `[a-z]([a-z0-9_]*[a-z0-9])*`
regexIndexMatchStart = 0
regexIndexMatchEnd = 1
regexIndexSubmatchStart = 2
regexIndexSubmatchEnd = 3
)
var snakeCaseRegex = regexp.MustCompile("^" + snakeCasePattern + "$") var snakeCaseRegex = regexp.MustCompile("^" + snakeCasePattern + "$")
...@@ -49,6 +56,29 @@ func ReplaceCaseInsensitive(string, toReplace, replaceWith string) string { ...@@ -49,6 +56,29 @@ func ReplaceCaseInsensitive(string, toReplace, replaceWith string) string {
return regex.ReplaceAllString(string, replaceWith) return regex.ReplaceAllString(string, replaceWith)
} }
// ReplaceAllRegexStringSubmatch finds the submatches for a regular expression that has a single capturing group and
// replaces all the submatches (i.e. the part that matches the capturing group) with replaceWith.
// E.g. the regular expression re = a(x*)b captures any number of x's that are between an a and b.
// ReplaceAllRegexStringSubmatch(re, "-axxb-ab-axb-x-ax-xb-ba-", "?") will result in "-a?b-a?b-a?b-x-ax-xb-ba-"
func ReplaceAllRegexStringSubmatch(re *regexp.Regexp, s string, replaceWith string) string {
result := ""
lastIndex := 0
for _, v := range re.FindAllSubmatchIndex([]byte(s), -1) {
if len(v) == regexIndexSubmatchEnd+1 {
// One submatch - replace the submatch with replaceWith
result += s[lastIndex:v[regexIndexSubmatchStart]] + replaceWith + s[v[regexIndexSubmatchEnd]:v[regexIndexMatchEnd]]
lastIndex = v[regexIndexMatchEnd]
} else {
// A normal match with no submatch - don't replace anything (this should not really happen)
result += s[lastIndex:v[regexIndexMatchEnd]]
}
lastIndex = v[regexIndexMatchEnd]
}
return result + s[lastIndex:]
}
// TrimQuotes - trims quotes from a string (ie: "foo" will return foo) // TrimQuotes - trims quotes from a string (ie: "foo" will return foo)
func TrimQuotes(stringToTrim string) string { func TrimQuotes(stringToTrim string) string {
if len(stringToTrim) >= 2 { if len(stringToTrim) >= 2 {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment