Skip to content

Commit

Permalink
feat: Enhance Error Redaction (#609)
Browse files Browse the repository at this point in the history
* feat: Enhance Error Redaction

* docs: DLP remarks

* chore(deps): Pin `karma-webpack`
  • Loading branch information
danielbankhead committed Apr 2, 2024
1 parent 3bb35c5 commit b1d2875
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 4 deletions.
6 changes: 6 additions & 0 deletions README.md
Expand Up @@ -160,6 +160,12 @@ over other authentication methods, i.e., application default credentials.
*
* Set `false` to disable.
*
* @remarks
*
* This does not replace the requirement for an active Data Loss Prevention (DLP) provider. For DLP suggestions, see:
* - https://cloud.google.com/sensitive-data-protection/docs/redacting-sensitive-data#dlp_deidentify_replace_infotype-nodejs
* - https://cloud.google.com/sensitive-data-protection/docs/infotypes-reference#credentials_and_secrets
*
* @experimental
*/
errorRedactor?: typeof defaultErrorRedactor | false;
Expand Down
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -68,7 +68,7 @@
"karma-mocha": "^2.0.0",
"karma-remap-coverage": "^0.1.5",
"karma-sourcemap-loader": "^0.4.0",
"karma-webpack": "^5.0.0",
"karma-webpack": "5.0.0",
"linkinator": "^4.0.0",
"mocha": "^8.0.0",
"multiparty": "^4.2.1",
Expand Down
30 changes: 29 additions & 1 deletion src/common.ts
Expand Up @@ -209,6 +209,12 @@ export interface GaxiosOptions {
/**
* An experimental error redactor.
*
* @remarks
*
* This does not replace the requirement for an active Data Loss Prevention (DLP) provider. For DLP suggestions, see:
* - https://cloud.google.com/sensitive-data-protection/docs/redacting-sensitive-data#dlp_deidentify_replace_infotype-nodejs
* - https://cloud.google.com/sensitive-data-protection/docs/infotypes-reference#credentials_and_secrets
*
* @experimental
*/
errorRedactor?: typeof defaultErrorRedactor | false;
Expand Down Expand Up @@ -359,6 +365,16 @@ export function defaultErrorRedactor<T = any>(data: {
if (/^authentication$/.test(key)) {
headers[key] = REDACT;
}

// any casing of `Authorization`
if (/^authorization$/.test(key)) {
headers[key] = REDACT;
}

// anything containing secret, such as 'client secret'
if (/secret/.test(key)) {
headers[key] = REDACT;
}
}
}

Expand All @@ -370,7 +386,11 @@ export function defaultErrorRedactor<T = any>(data: {
) {
const text = obj[key];

if (/grant_type=/.test(text) || /assertion=/.test(text)) {
if (
/grant_type=/.test(text) ||
/assertion=/.test(text) ||
/secret/.test(text)
) {
obj[key] = REDACT;
}
}
Expand All @@ -385,6 +405,10 @@ export function defaultErrorRedactor<T = any>(data: {
if ('assertion' in obj) {
obj['assertion'] = REDACT;
}

if ('client_secret' in obj) {
obj['client_secret'] = REDACT;
}
}
}

Expand All @@ -404,6 +428,10 @@ export function defaultErrorRedactor<T = any>(data: {
url.searchParams.set('token', REDACT);
}

if (url.searchParams.has('client_secret')) {
url.searchParams.set('client_secret', REDACT);
}

data.config.url = url.toString();
} catch {
// ignore error - no need to parse an invalid URL
Expand Down
12 changes: 10 additions & 2 deletions test/test.getch.ts
Expand Up @@ -704,20 +704,23 @@ describe('🎏 data handling', () => {

const customURL = new URL(url);
customURL.searchParams.append('token', 'sensitive');
customURL.searchParams.append('client_secret', 'data');
customURL.searchParams.append('random', 'non-sensitive');

const config: GaxiosOptions = {
headers: {
authentication: 'My Auth',
authorization: 'My Auth',
'content-type': 'application/x-www-form-urlencoded',
random: 'data',
},
data: {
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
assertion: 'somesensitivedata',
unrelated: 'data',
client_secret: 'data',
},
body: 'grant_type=somesensitivedata&assertion=somesensitivedata',
body: 'grant_type=somesensitivedata&assertion=somesensitivedata&client_secret=data',
};

// simulate JSON response
Expand Down Expand Up @@ -756,13 +759,15 @@ describe('🎏 data handling', () => {
assert.deepStrictEqual(e.config.headers, {
...config.headers, // non-redactables should be present
authentication: REDACT,
authorization: REDACT,
});

// config redactions - data
assert.deepStrictEqual(e.config.data, {
...config.data, // non-redactables should be present
grant_type: REDACT,
assertion: REDACT,
client_secret: REDACT,
});

// config redactions - body
Expand All @@ -773,6 +778,7 @@ describe('🎏 data handling', () => {
const resultURL = new URL(e.config.url);
assert.notDeepStrictEqual(resultURL.toString(), customURL.toString());
customURL.searchParams.set('token', REDACT);
customURL.searchParams.set('client_secret', REDACT);
assert.deepStrictEqual(resultURL.toString(), customURL.toString());

// response redactions
Expand All @@ -781,11 +787,13 @@ describe('🎏 data handling', () => {
assert.deepStrictEqual(e.response.headers, {
...responseHeaders, // non-redactables should be present
authentication: REDACT,
authorization: REDACT,
});
assert.deepStrictEqual(e.response.data, {
...response, // non-redactables should be present
grant_type: REDACT,
assertion: REDACT,
client_secret: REDACT,
grant_type: REDACT,
});
} finally {
scope.done();
Expand Down

0 comments on commit b1d2875

Please sign in to comment.