fix: escape formula characters in contact CSV export (#15334)
## Description Contact export builds its CSV with the standard library `CSV`, which writes user-supplied values (name, email, phone, custom attributes) verbatim. When a cell begins with a formula character (`=`, `+`, `-`, `@`, and tab/CR), spreadsheet applications interpret it as a formula on open. This switches the export to `CSVSafe` (the `csv-safe` gem already used by the v2 report exports), which prefixes such fields so they are treated as text. No new dependency, no behavioural change beyond neutralising formula-leading cells. Note: phone numbers stored with a leading `+` are now prefixed with a single quote in the exported file, consistent with how the report exports already behave. Ref https://linear.app/chatwoot/issue/CW-7473 ## Type of change - [x] Bug fix (non-breaking change which fixes an issue) ## How Has This Been Tested? `bundle exec rspec spec/jobs/account/contacts_export_job_spec.rb` — added a case asserting a formula-leading contact value is neutralised on export; existing cases updated for the phone-number prefix. ## Checklist: - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my code - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes
This commit is contained in:
@@ -81,7 +81,20 @@ RSpec.describe Account::ContactsExportJob do
|
||||
expect(csv_data.length).to eq(account.contacts.count)
|
||||
|
||||
expect(emails).to include('test1@text.example', 'test2@text.example')
|
||||
expect(phone_numbers).to include('+910808080818', '+910808080808')
|
||||
# Phone numbers lead with "+" (a formula character), so they are prefixed with "'" on export.
|
||||
expect(phone_numbers).to include("'+910808080818", "'+910808080808")
|
||||
end
|
||||
|
||||
it 'neutralises formula-leading characters in exported values' do
|
||||
create(:contact, account: account, name: '=HYPERLINK("http://evil.example")', email: 'formula@text.example')
|
||||
|
||||
described_class.perform_now(account.id, user.id, %w[id name email], {})
|
||||
|
||||
csv_content = account.contacts_export.download.force_encoding('UTF-8').delete_prefix("\xEF\xBB\xBF")
|
||||
csv_data = CSV.parse(csv_content, headers: true)
|
||||
row = csv_data.find { |r| r['email'] == 'formula@text.example' }
|
||||
|
||||
expect(row['name']).to start_with("'")
|
||||
end
|
||||
|
||||
it 'exports labels when requested through column names' do
|
||||
|
||||
Reference in New Issue
Block a user