Skip to content

Commit

Permalink
[Excel Analyzer] add spreadsheet received callback
Browse files Browse the repository at this point in the history
Allow Alaveteli to take action if an email contains an Excel
spreadsheet.
  • Loading branch information
gbp committed Feb 9, 2024
1 parent bd6a193 commit d4f8c63
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 3 deletions.
11 changes: 11 additions & 0 deletions gems/excel_analyzer/lib/excel_analyzer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@
# detect hidden data within spreadsheet attachments in emails. It supports .xls
# and .xlsx file formats.
module ExcelAnalyzer
# A configurable callable that gets executed when an email with a spreadsheet
# attachment is analyzed. This allows for custom handling of the spreadsheet
# data.
#
# @example Set a custom callable to handle received spreadsheets
# ExcelAnalyzer.on_spreadsheet_received = ->(blob) { process(blob) }
#
# @!attribute [rw] on_spreadsheet_received
# @return [Proc] the callable to run for spreadsheet attachments
mattr_accessor :on_spreadsheet_received, default: ->(blob) {}

# Provides the list of content types that the ExcelAnalyzer will attempt to
# analyze in search of hidden data. It currently includes content types for
# .xls and .xlsx files.
Expand Down
6 changes: 5 additions & 1 deletion gems/excel_analyzer/lib/excel_analyzer/eml_analyzer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ def metadata
_1[:content_type]
end

return { content_types: }
if content_types.any? { ExcelAnalyzer.content_types.include?(_1) }
# rubocop:disable Style/RescueModifier
ExcelAnalyzer.on_spreadsheet_received.call(blob) rescue nil
# rubocop:enable Style/RescueModifier
end
end

{}
Expand Down
54 changes: 52 additions & 2 deletions gems/excel_analyzer/spec/excel_analyzer/eml_analyzer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,15 @@
end

describe "#metadata" do
around do |example|
original_callback = ExcelAnalyzer.on_spreadsheet_received
ExcelAnalyzer.on_spreadsheet_received = ->(blob) {}
example.call
ExcelAnalyzer.on_spreadsheet_received = original_callback
end

let(:mail) do
Mail.new { add_file File.join(__dir__, "../fixtures/data.xls") }
Mail.new { add_file File.join(__dir__, "../fixtures/plain.txt") }
end

let(:io) { double(:File, path: "blob/path") }
Expand All @@ -30,6 +37,49 @@

before { allow(Mail).to receive(:read).with("blob/path").and_return(mail) }

it { is_expected.to include(content_types: ["application/vnd.ms-excel"]) }
it { is_expected.to eq({}) }

context "when mail contains XLS attachment" do
let(:mail) do
Mail.new { add_file File.join(__dir__, "../fixtures/data.xls") }
end

it { is_expected.to eq({}) }

it "calls on_spreadsheet_received callback" do
expect(ExcelAnalyzer.on_spreadsheet_received).
to receive(:call).with(blob)
metadata
end
end

context "when mail contains XLSX attachment" do
let(:mail) do
Mail.new { add_file File.join(__dir__, "../fixtures/data.xlsx") }
end

it { is_expected.to eq({}) }
it "calls on_spreadsheet_received callback" do
expect(ExcelAnalyzer.on_spreadsheet_received).
to receive(:call).with(blob)
metadata
end
end

context "when mail contains XLS and XLSX attachment" do
let(:mail) do
Mail.new do
add_file File.join(__dir__, "../fixtures/data.xls")
add_file File.join(__dir__, "../fixtures/data.xlsx")
end
end

it { is_expected.to eq({}) }
it "calls on_spreadsheet_received callback once only" do
expect(ExcelAnalyzer.on_spreadsheet_received).
to receive(:call).with(blob).once
metadata
end
end
end
end

0 comments on commit d4f8c63

Please sign in to comment.