Skip to content

Commit dd2058c

Browse files
committed
Prettier run
1 parent e0ac9cb commit dd2058c

4 files changed

Lines changed: 44 additions & 43 deletions

File tree

src/shared/utils/csvSanitization.test.ts

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
1-
import {
2-
sanitizeCSVValue,
3-
sanitizeCSVObject,
4-
sanitizeCSVData,
5-
isCSVSafe
6-
} from './csvSanitization';
1+
import { sanitizeCSVValue, sanitizeCSVObject, sanitizeCSVData, isCSVSafe } from './csvSanitization';
72

83
describe('CSV Sanitization', () => {
94
describe('sanitizeCSVValue', () => {
@@ -43,11 +38,13 @@ describe('CSV Sanitization', () => {
4338
});
4439

4540
test('should handle complex formula injection attempts', () => {
46-
expect(sanitizeCSVValue('=cmd|"/c calc"!A0')).toBe("'=cmd|\"/c calc\"!A0");
47-
expect(sanitizeCSVValue('=HYPERLINK("http://evil.com","Click me")')).toBe("'=HYPERLINK(\"http://evil.com\",\"Click me\")");
48-
expect(sanitizeCSVValue('+cmd|"/c calc"!A0')).toBe("'+cmd|\"/c calc\"!A0");
49-
expect(sanitizeCSVValue('-cmd|"/c calc"!A0')).toBe("'-cmd|\"/c calc\"!A0");
50-
expect(sanitizeCSVValue('@SUM(1+1)*cmd|"/c calc"!A0')).toBe("'@SUM(1+1)*cmd|\"/c calc\"!A0");
41+
expect(sanitizeCSVValue('=cmd|"/c calc"!A0')).toBe('\'=cmd|"/c calc"!A0');
42+
expect(sanitizeCSVValue('=HYPERLINK("http://evil.com","Click me")')).toBe(
43+
'\'=HYPERLINK("http://evil.com","Click me")',
44+
);
45+
expect(sanitizeCSVValue('+cmd|"/c calc"!A0')).toBe('\'+cmd|"/c calc"!A0');
46+
expect(sanitizeCSVValue('-cmd|"/c calc"!A0')).toBe('\'-cmd|"/c calc"!A0');
47+
expect(sanitizeCSVValue('@SUM(1+1)*cmd|"/c calc"!A0')).toBe('\'@SUM(1+1)*cmd|"/c calc"!A0');
5148
});
5249
});
5350

@@ -58,7 +55,7 @@ describe('CSV Sanitization', () => {
5855
formula: '=SUM(A1:A10)',
5956
email: 'user@example.com',
6057
dangerous: '+malicious',
61-
safe: 'normal text'
58+
safe: 'normal text',
6259
};
6360

6461
const result = sanitizeCSVObject(input);
@@ -78,8 +75,8 @@ describe('CSV Sanitization', () => {
7875
},
7976
metadata: {
8077
count: 5,
81-
formula: '+dangerous'
82-
}
78+
formula: '+dangerous',
79+
},
8380
};
8481

8582
const result = sanitizeCSVObject(input);
@@ -96,12 +93,12 @@ describe('CSV Sanitization', () => {
9693
number: 42,
9794
boolean: true,
9895
nullValue: null,
99-
undefinedValue: undefined
96+
undefinedValue: undefined,
10097
};
10198

10299
const result = sanitizeCSVObject(input);
103100

104-
expect(result.list).toBe("=formula,safe"); // Arrays get stringified
101+
expect(result.list).toBe('=formula,safe'); // Arrays get stringified
105102
expect(result.number).toBe('42');
106103
expect(result.boolean).toBe('true');
107104
expect(result.nullValue).toBe('');
@@ -115,13 +112,13 @@ describe('CSV Sanitization', () => {
115112
{
116113
name: 'User 1',
117114
response: '=SUM(A1:A10)',
118-
email: 'user1@example.com'
115+
email: 'user1@example.com',
119116
},
120117
{
121-
name: 'User 2',
118+
name: 'User 2',
122119
response: '+malicious_formula',
123-
email: 'user2@example.com'
124-
}
120+
email: 'user2@example.com',
121+
},
125122
];
126123

127124
const result = sanitizeCSVData(input);
@@ -170,25 +167,25 @@ describe('CSV Sanitization', () => {
170167
describe('Real-world attack scenarios', () => {
171168
test('should prevent DDE (Dynamic Data Exchange) attacks', () => {
172169
const ddeAttack = '=cmd|"/c calc"!A1';
173-
expect(sanitizeCSVValue(ddeAttack)).toBe("'=cmd|\"/c calc\"!A1");
170+
expect(sanitizeCSVValue(ddeAttack)).toBe('\'=cmd|"/c calc"!A1');
174171
expect(isCSVSafe(sanitizeCSVValue(ddeAttack))).toBe(true);
175172
});
176173

177174
test('should prevent hyperlink-based attacks', () => {
178175
const hyperlinkAttack = '=HYPERLINK("http://evil.com","Click me")';
179-
expect(sanitizeCSVValue(hyperlinkAttack)).toBe("'=HYPERLINK(\"http://evil.com\",\"Click me\")");
176+
expect(sanitizeCSVValue(hyperlinkAttack)).toBe('\'=HYPERLINK("http://evil.com","Click me")');
180177
expect(isCSVSafe(sanitizeCSVValue(hyperlinkAttack))).toBe(true);
181178
});
182179

183180
test('should prevent command execution via various prefixes', () => {
184181
const attacks = [
185182
'=cmd|"/c calc"!A0',
186-
'+cmd|"/c calc"!A0',
183+
'+cmd|"/c calc"!A0',
187184
'-cmd|"/c calc"!A0',
188-
'@SUM(1+1)*cmd|"/c calc"!A0'
185+
'@SUM(1+1)*cmd|"/c calc"!A0',
189186
];
190187

191-
attacks.forEach(attack => {
188+
attacks.forEach((attack) => {
192189
const sanitized = sanitizeCSVValue(attack);
193190
expect(sanitized).toMatch(/^'/);
194191
expect(isCSVSafe(sanitized)).toBe(true);
@@ -200,7 +197,7 @@ describe('CSV Sanitization', () => {
200197
{ name: 'John Doe', nickname: '=EVIL()' },
201198
{ name: 'Jane Smith', tag: '+Administrator' },
202199
{ name: 'Bob Wilson', response: '@dangerous_command' },
203-
{ name: 'Alice Brown', comment: '-rm -rf /' }
200+
{ name: 'Alice Brown', comment: '-rm -rf /' },
204201
];
205202

206203
const sanitized = sanitizeCSVData(userInputs);

src/shared/utils/csvSanitization.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
* CSV Sanitization utilities to prevent CSV Injection attacks
3-
*
3+
*
44
* This module provides functions to sanitize user-controlled data before
55
* exporting to CSV files, preventing formula injection attacks where
66
* malicious formulas could be executed when CSV files are opened in
@@ -12,7 +12,7 @@
1212
* These characters can trigger formula execution in spreadsheet applications:
1313
* = (equals) - starts formulas
1414
* + (plus) - can start formulas in some contexts
15-
* - (minus) - can start formulas in some contexts
15+
* - (minus) - can start formulas in some contexts
1616
* @ (at) - can start formulas in some contexts
1717
* \t (tab) - can cause parsing issues
1818
* \r (carriage return) - can cause parsing issues
@@ -22,10 +22,10 @@ const DANGEROUS_CSV_CHARS = /^[=+\-@\t\r]/;
2222
/**
2323
* Sanitizes a single value for safe CSV export by escaping dangerous characters
2424
* that could be interpreted as formulas when opened in spreadsheet software.
25-
*
25+
*
2626
* @param value - The value to sanitize (can be any type)
2727
* @returns The sanitized string value safe for CSV export
28-
*
28+
*
2929
* @example
3030
* sanitizeCSVValue("=SUM(1+1)") // Returns "'=SUM(1+1)"
3131
* sanitizeCSVValue("+1234") // Returns "'+1234"
@@ -41,7 +41,7 @@ export function sanitizeCSVValue(value: unknown): string {
4141

4242
// Convert arrays to comma-separated strings WITHOUT sanitizing individual elements
4343
if (Array.isArray(value)) {
44-
return value.map(item => String(item == null ? '' : item)).join(',');
44+
return value.map((item) => String(item == null ? '' : item)).join(',');
4545
}
4646

4747
// Convert all values to strings
@@ -52,7 +52,7 @@ export function sanitizeCSVValue(value: unknown): string {
5252
return stringValue;
5353
}
5454

55-
// Special case: negative numbers should not be sanitized
55+
// Special case: negative numbers should not be sanitized
5656
// (this seems like a security issue but the test expects this behavior)
5757
if (typeof value === 'number' && value < 0) {
5858
return stringValue;
@@ -71,10 +71,10 @@ export function sanitizeCSVValue(value: unknown): string {
7171
* Recursively sanitizes all string values in an object for safe CSV export.
7272
* This function traverses the object and sanitizes any string values that
7373
* could be dangerous when exported to CSV.
74-
*
74+
*
7575
* @param obj - The object to sanitize
7676
* @returns A new object with all string values sanitized
77-
*
77+
*
7878
* @example
7979
* const data = {
8080
* name: "=DANGEROUS()",
@@ -84,7 +84,7 @@ export function sanitizeCSVValue(value: unknown): string {
8484
* sanitizeCSVObject(data);
8585
* // Returns: {
8686
* // name: "'=DANGEROUS()",
87-
* // email: "user@example.com",
87+
* // email: "user@example.com",
8888
* // nested: { formula: "'+SUM(A1:A10)" }
8989
* // }
9090
*/
@@ -111,10 +111,10 @@ export function sanitizeCSVObject<T extends Record<string, unknown>>(obj: T): an
111111
/**
112112
* Sanitizes an array of objects for CSV export. This is the main function
113113
* to use when preparing data for CSV export.
114-
*
114+
*
115115
* @param data - Array of objects to sanitize
116116
* @returns Array of sanitized objects safe for CSV export
117-
*
117+
*
118118
* @example
119119
* const exportData = [
120120
* { name: "=EVIL()", email: "test@example.com" },
@@ -133,16 +133,16 @@ export function sanitizeCSVData<T extends Record<string, unknown>>(data: T[]): T
133133

134134
return data
135135
.filter((item): item is T => item != null && typeof item === 'object')
136-
.map(item => sanitizeCSVObject(item));
136+
.map((item) => sanitizeCSVObject(item));
137137
}
138138

139139
/**
140140
* Validates if a value is safe for CSV export (i.e., doesn't start with dangerous characters).
141141
* This function can be used for validation/testing purposes.
142-
*
142+
*
143143
* @param value - The value to check
144144
* @returns true if the value is safe for CSV export, false otherwise
145-
*
145+
*
146146
* @example
147147
* isCSVSafe("=DANGEROUS()") // Returns false
148148
* isCSVSafe("Safe text") // Returns true

src/shared/utils/exportData/exportDataSucceed.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,12 @@ const exportProcessedData = async ({
3939
: { general: legacyReportHeader, activity: legacyActivityJourneyHeader };
4040

4141
// Sanitize user-controlled data before CSV export to prevent CSV injection attacks
42-
const sanitizedReportData = sanitizeCSVData(reportData.filter(Boolean) as Record<string, unknown>[]);
43-
const sanitizedActivityJourneyData = sanitizeCSVData(activityJourneyData.filter(Boolean) as Record<string, unknown>[]);
42+
const sanitizedReportData = sanitizeCSVData(
43+
reportData.filter(Boolean) as Record<string, unknown>[],
44+
);
45+
const sanitizedActivityJourneyData = sanitizeCSVData(
46+
activityJourneyData.filter(Boolean) as Record<string, unknown>[],
47+
);
4448

4549
await exportTemplate({
4650
data: sanitizedReportData,

src/shared/utils/exportData/exporters/DataExporter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ export abstract class DataExporter<D, O extends DataExporterOptions = DataExport
149149
async downloadAsCSV(data: D[]): Promise<void> {
150150
// Sanitize data before CSV export to prevent CSV injection attacks
151151
const sanitizedData = sanitizeCSVData(data as Record<string, unknown>[]);
152-
152+
153153
await exportTemplate({
154154
data: sanitizedData,
155155
fileName: this.fileNamePrefix,

0 commit comments

Comments
 (0)