Fix parsing of Error objects when redacting (#18777)

* Fix parsing of Error objects when redacting

* Create perfect-ducks-add.md

* Move errorReplacer into redact util

* Use unknown instead of any

Co-authored-by: Pascal Jufer <pascal-jufer@bluewin.ch>

---------

Co-authored-by: Pascal Jufer <pascal-jufer@bluewin.ch>
This commit is contained in:
ian
2023-05-31 20:40:32 +08:00
committed by GitHub
parent d6c0d31b39
commit cd344baac4
3 changed files with 90 additions and 3 deletions

View File

@@ -0,0 +1,5 @@
---
"@directus/api": patch
---
Fixed parsing of Error objects when redacting

View File

@@ -1,7 +1,7 @@
import { REDACTED_TEXT } from '@directus/constants';
import { merge } from 'lodash-es';
import { expect, test } from 'vitest';
import { redact } from './redact.js';
import { describe, expect, test } from 'vitest';
import { errorReplacer, redact } from './redact.js';
const input = {
$trigger: {
@@ -142,3 +142,69 @@ test('should support multiple paths', () => {
})
);
});
describe('errorReplacer tests', () => {
test('Returns parsed error object', () => {
const errorMessage = 'Error Message';
const errorCause = 'Error Cause';
const result = errorReplacer('', new Error(errorMessage, { cause: errorCause }));
expect(result.name).toBe('Error');
expect(result.message).toBe(errorMessage);
expect(result.stack).toBeDefined();
expect(result.cause).toBe(errorCause);
});
test('Returns other types as is', () => {
const values = [
undefined,
null,
0,
1,
true,
false,
'',
'abc',
[],
['123'],
{},
{ abc: '123' },
() => {
// empty
},
];
for (const value of values) {
expect(errorReplacer('', value)).toBe(value);
}
});
test('Correctly parses error object when used with JSON.stringify()', () => {
const errorMessage = 'Error Message';
const errorCause = 'Error Cause';
const baseValue = {
string: 'abc',
num: 123,
bool: true,
null: null,
};
const objWithError = {
...baseValue,
error: new Error(errorMessage, { cause: errorCause }),
};
const expectedResult = {
...baseValue,
error: { name: 'Error', message: errorMessage, cause: errorCause },
};
const result = JSON.parse(JSON.stringify(objWithError, errorReplacer));
// Stack changes depending on env
expect(result.error.stack).toBeDefined();
delete result.error.stack;
expect(result).toStrictEqual(expectedResult);
});
});

View File

@@ -13,7 +13,7 @@ type Paths = string[][];
export function redact(input: UnknownObject, paths: Paths, replacement: string): UnknownObject {
const wildcardChars = ['*', '**'];
const clone = structuredClone(input);
const clone = JSON.parse(JSON.stringify(input, errorReplacer));
const visited = new WeakSet<UnknownObject>();
traverse(clone, paths);
@@ -86,3 +86,19 @@ export function redact(input: UnknownObject, paths: Paths, replacement: string):
}
}
}
/**
* Extract values from Error objects for use with JSON.stringify()
*/
export function errorReplacer(_key: string, value: unknown) {
if (value instanceof Error) {
return {
name: value.name,
message: value.message,
stack: value.stack,
cause: value.cause,
};
}
return value;
}