|
| 1 | +// Copyright (c) Microsoft Corporation. All rights reserved. |
| 2 | +// Licensed under the MIT License. |
| 3 | + |
| 4 | +// this file contains a set of default sanitizers applied to all recordings |
| 5 | + |
| 6 | +package recording |
| 7 | + |
| 8 | +import ( |
| 9 | + "bytes" |
| 10 | + "encoding/json" |
| 11 | + "fmt" |
| 12 | + "io" |
| 13 | + "net/http" |
| 14 | +) |
| 15 | + |
| 16 | +// sanitizer represents a single sanitizer configured via the test proxy's /Admin/AddSanitizers endpoint |
| 17 | +type sanitizer struct { |
| 18 | + // Name is the name of a sanitizer type e.g. "BodyKeySanitizer" |
| 19 | + Name string `json:"Name,omitempty"` |
| 20 | + Body sanitizerBody `json:"Body,omitempty"` |
| 21 | +} |
| 22 | + |
| 23 | +type sanitizerBody struct { |
| 24 | + // GroupForReplace is the name of the regex group to replace |
| 25 | + GroupForReplace string `json:"groupForReplace,omitempty"` |
| 26 | + // JSONPath is the JSON path to the value to replace |
| 27 | + JSONPath string `json:"jsonPath,omitempty"` |
| 28 | + // Key is the name of a header to sanitize |
| 29 | + Key string `json:"key,omitempty"` |
| 30 | + // Regex is the regular expression to match a value to sanitize |
| 31 | + Regex string `json:"regex,omitempty"` |
| 32 | + // Value is the string that replaces the matched value. The sanitizers in |
| 33 | + // this file accept the test proxy's default Value, "Sanitized". |
| 34 | + Value string `json:"value,omitempty"` |
| 35 | +} |
| 36 | + |
| 37 | +func newBodyKeySanitizer(jsonPath string) sanitizer { |
| 38 | + return sanitizer{ |
| 39 | + Name: "BodyKeySanitizer", |
| 40 | + Body: sanitizerBody{ |
| 41 | + JSONPath: jsonPath, |
| 42 | + }, |
| 43 | + } |
| 44 | +} |
| 45 | + |
| 46 | +func newBodyRegexSanitizer(regex, groupForReplace string) sanitizer { |
| 47 | + return sanitizer{ |
| 48 | + Name: "BodyRegexSanitizer", |
| 49 | + Body: sanitizerBody{ |
| 50 | + GroupForReplace: groupForReplace, |
| 51 | + Regex: regex, |
| 52 | + }, |
| 53 | + } |
| 54 | +} |
| 55 | + |
| 56 | +func newGeneralRegexSanitizer(regex, groupForReplace string) sanitizer { |
| 57 | + return sanitizer{ |
| 58 | + Name: "GeneralRegexSanitizer", |
| 59 | + Body: sanitizerBody{ |
| 60 | + GroupForReplace: groupForReplace, |
| 61 | + Regex: regex, |
| 62 | + }, |
| 63 | + } |
| 64 | +} |
| 65 | + |
| 66 | +func newHeaderRegexSanitizer(key, regex, groupForReplace string) sanitizer { |
| 67 | + return sanitizer{ |
| 68 | + Name: "HeaderRegexSanitizer", |
| 69 | + Body: sanitizerBody{ |
| 70 | + GroupForReplace: groupForReplace, |
| 71 | + Key: key, |
| 72 | + Regex: regex, |
| 73 | + }, |
| 74 | + } |
| 75 | +} |
| 76 | + |
| 77 | +// addSanitizers adds an arbitrary number of sanitizers with a single request. It |
| 78 | +// isn't exported because SDK modules don't add enough sanitizers to benefit from it. |
| 79 | +func addSanitizers(s []sanitizer, options *RecordingOptions) error { |
| 80 | + if options == nil { |
| 81 | + options = defaultOptions() |
| 82 | + } |
| 83 | + url := fmt.Sprintf("%s/Admin/AddSanitizers", options.baseURL()) |
| 84 | + req, err := http.NewRequest(http.MethodPost, url, nil) |
| 85 | + if err != nil { |
| 86 | + return err |
| 87 | + } |
| 88 | + handleTestLevelSanitizer(req, options) |
| 89 | + b, err := json.Marshal(s) |
| 90 | + if err != nil { |
| 91 | + return err |
| 92 | + } |
| 93 | + req.Body = io.NopCloser(bytes.NewReader(b)) |
| 94 | + req.ContentLength = int64(len(b)) |
| 95 | + req.Header.Set("Content-Type", "application/json") |
| 96 | + return handleProxyResponse(client.Do(req)) |
| 97 | +} |
| 98 | + |
| 99 | +var defaultSanitizers = []sanitizer{ |
| 100 | + newGeneralRegexSanitizer(`("|;)Secret=(?<secret>[^;]+)`, "secret"), |
| 101 | + newBodyKeySanitizer("$..refresh_token"), |
| 102 | + newHeaderRegexSanitizer("api-key", "", ""), |
| 103 | + newBodyKeySanitizer("$..access_token"), |
| 104 | + newBodyKeySanitizer("$..connectionString"), |
| 105 | + newBodyKeySanitizer("$..applicationSecret"), |
| 106 | + newBodyKeySanitizer("$..apiKey"), |
| 107 | + newBodyRegexSanitizer(`client_secret=(?<secret>[^&"]+)`, "secret"), |
| 108 | + newBodyRegexSanitizer(`client_assertion=(?<secret>[^&"]+)`, "secret"), |
| 109 | + newHeaderRegexSanitizer("x-ms-rename-source", "", ""), |
| 110 | + newHeaderRegexSanitizer("x-ms-file-rename-source-authorization", "", ""), |
| 111 | + newHeaderRegexSanitizer("x-ms-file-rename-source", "", ""), |
| 112 | + newHeaderRegexSanitizer("x-ms-encryption-key-sha256", "", ""), |
| 113 | + newHeaderRegexSanitizer("x-ms-encryption-key", "", ""), |
| 114 | + newHeaderRegexSanitizer("x-ms-copy-source-authorization", "", ""), |
| 115 | + newHeaderRegexSanitizer("x-ms-copy-source", "", ""), |
| 116 | + newBodyRegexSanitizer("token=(?<token>[^&]+)($|&)", "token"), |
| 117 | + newHeaderRegexSanitizer("subscription-key", "", ""), |
| 118 | + newBodyKeySanitizer("$..sshPassword"), |
| 119 | + newBodyKeySanitizer("$..secondaryKey"), |
| 120 | + newBodyKeySanitizer("$..runAsPassword"), |
| 121 | + newBodyKeySanitizer("$..primaryKey"), |
| 122 | + newHeaderRegexSanitizer("Location", "", ""), |
| 123 | + newGeneralRegexSanitizer(`("|;)[Aa]ccess[Kk]ey=(?<secret>[^;]+)`, "secret"), |
| 124 | + newGeneralRegexSanitizer(`("|;)[Aa]ccount[Kk]ey=(?<secret>[^;]+)`, "secret"), |
| 125 | + newBodyKeySanitizer("$..aliasSecondaryConnectionString"), |
| 126 | + newGeneralRegexSanitizer(`("|;)[Ss]hared[Aa]ccess[Kk]ey=(?<secret>[^;\"]+)`, "secret"), |
| 127 | + newHeaderRegexSanitizer("aeg-sas-token", "", ""), |
| 128 | + newHeaderRegexSanitizer("aeg-sas-key", "", ""), |
| 129 | + newHeaderRegexSanitizer("aeg-channel-name", "", ""), |
| 130 | + newBodyKeySanitizer("$..adminPassword"), |
| 131 | + newBodyKeySanitizer("$..administratorLoginPassword"), |
| 132 | + newBodyKeySanitizer("$..accessToken"), |
| 133 | + newBodyKeySanitizer("$..accessSAS"), |
| 134 | + newGeneralRegexSanitizer(`(?:(sv|sig|se|srt|ss|sp)=)(?<secret>[^&\"]+)`, "secret"), // SAS tokens |
| 135 | + newBodyKeySanitizer("$.value[*].key"), |
| 136 | + newBodyKeySanitizer("$.key"), |
| 137 | + newBodyKeySanitizer("$..userId"), |
| 138 | + newBodyKeySanitizer("$..urlSource"), |
| 139 | + newBodyKeySanitizer("$..uploadUrl"), |
| 140 | + newBodyKeySanitizer("$..token"), |
| 141 | + newBodyKeySanitizer("$..to"), |
| 142 | + newBodyKeySanitizer("$..tenantId"), |
| 143 | + newBodyKeySanitizer("$..targetResourceId"), |
| 144 | + newBodyKeySanitizer("$..targetModelLocation"), |
| 145 | + newBodyKeySanitizer("$..storageContainerWriteSas"), |
| 146 | + newBodyKeySanitizer("$..storageContainerUri"), |
| 147 | + newBodyKeySanitizer("$..storageContainerReadListSas"), |
| 148 | + newBodyKeySanitizer("$..storageAccountPrimaryKey"), |
| 149 | + newBodyKeySanitizer("$..storageAccount"), |
| 150 | + newBodyKeySanitizer("$..source"), |
| 151 | + newBodyKeySanitizer("$..secondaryReadonlyMasterKey"), |
| 152 | + newBodyKeySanitizer("$..secondaryMasterKey"), |
| 153 | + newBodyKeySanitizer("$..secondaryConnectionString"), |
| 154 | + newBodyKeySanitizer("$..scriptUrlSasToken"), |
| 155 | + newBodyKeySanitizer("$..scan"), |
| 156 | + newBodyKeySanitizer("$..sasUri"), |
| 157 | + newBodyKeySanitizer("$..resourceGroup"), |
| 158 | + newBodyKeySanitizer("$..privateKey"), |
| 159 | + newBodyKeySanitizer("$..principalId"), |
| 160 | + newBodyKeySanitizer("$..primaryReadonlyMasterKey"), |
| 161 | + newBodyKeySanitizer("$..primaryMasterKey"), |
| 162 | + newBodyKeySanitizer("$..primaryConnectionString"), |
| 163 | + newBodyKeySanitizer("$..password"), |
| 164 | + newBodyKeySanitizer("$..outputDataUri"), |
| 165 | + newBodyKeySanitizer("$..managedResourceGroupName"), |
| 166 | + newBodyKeySanitizer("$..logLink"), |
| 167 | + newBodyKeySanitizer("$..lastModifiedBy"), |
| 168 | + newBodyKeySanitizer("$..keyVaultClientSecret"), |
| 169 | + newBodyKeySanitizer("$..inputDataUri"), |
| 170 | + newBodyKeySanitizer("$..id"), |
| 171 | + newBodyKeySanitizer("$..httpHeader"), |
| 172 | + newBodyKeySanitizer("$..guardian"), |
| 173 | + newBodyKeySanitizer("$..functionKey"), |
| 174 | + newBodyKeySanitizer("$..from"), |
| 175 | + newBodyKeySanitizer("$..fencingClientPassword"), |
| 176 | + newBodyKeySanitizer("$..encryptedCredential"), |
| 177 | + newBodyKeySanitizer("$..credential"), |
| 178 | + newBodyKeySanitizer("$..createdBy"), |
| 179 | + newBodyKeySanitizer("$..containerUri"), |
| 180 | + newBodyKeySanitizer("$..clientSecret"), |
| 181 | + newBodyKeySanitizer("$..certificatePassword"), |
| 182 | + newBodyKeySanitizer("$..catalog"), |
| 183 | + newBodyKeySanitizer("$..azureBlobSource.containerUrl"), |
| 184 | + newBodyKeySanitizer("$..authHeader"), |
| 185 | + newBodyKeySanitizer("$..atlasKafkaSecondaryEndpoint"), |
| 186 | + newBodyKeySanitizer("$..atlasKafkaPrimaryEndpoint"), |
| 187 | + newBodyKeySanitizer("$..appkey"), |
| 188 | + newBodyKeySanitizer("$..appId"), |
| 189 | + newBodyKeySanitizer("$..acrToken"), |
| 190 | + newBodyKeySanitizer("$..accountKey"), |
| 191 | + newBodyKeySanitizer("$..AccessToken"), |
| 192 | + newBodyKeySanitizer("$..WEBSITE_AUTH_ENCRYPTION_KEY"), |
| 193 | + newBodyRegexSanitizer("-----BEGIN PRIVATE KEY-----\\\\n(?<key>.+\\\\n)*-----END PRIVATE KEY-----\\\\n", "key"), |
| 194 | + newBodyKeySanitizer("$..adminPassword.value"), |
| 195 | + newBodyKeySanitizer("$..decryptionKey"), |
| 196 | +} |
0 commit comments