Scan for Malware with Ruby
Use AttachmentScanner to scan files and URLs for viruses and malware using Faraday with multipart support.
Scan a URL
The simplest way to scan — pass a URL and get back a result:
require "faraday"
conn = Faraday.new(SCANNER_URL) do |f|
f.request :authorization, "Bearer", API_TOKEN
f.request :json
f.response :json
end
response = conn.post("/v1.0/scans") do |req|
req.body = { url: "https://www.attachmentscanner.com/eicar.com" }
end
puts response.body["status"] # => "found"
puts response.body["matches"] # => ["Eicar-Test-File-Signature"]
Scan a File
Upload a file directly from disk:
require "faraday"
require "faraday/multipart"
conn = Faraday.new(SCANNER_URL) do |f|
f.request :authorization, "Bearer", API_TOKEN
f.request :multipart
f.response :json
end
response = conn.post("/v1.0/scans") do |req|
req.body = {
file: Faraday::Multipart::FilePart.new(
"/path/to/file.pdf",
"application/pdf",
"file.pdf"
)
}
end
puts response.body["status"] # => "ok" if clean, "found" if malware detected
Async Scan with Callback
For large files or non-blocking workflows, use async: true with a callback URL.
The API returns immediately with a pending status and POSTs the result to your callback
when the scan completes:
# 1. Submit the scan
conn = Faraday.new(SCANNER_URL) do |f|
f.request :authorization, "Bearer", API_TOKEN
f.request :json
f.response :json
end
response = conn.post("/v1.0/scans") do |req|
req.body = {
url: "https://example.com/large-file.zip",
async: true,
callback: "https://your-app.com/webhooks/scan-complete"
}
end
scan_id = response.body["id"] # => "a1b2c3d4-..."
status = response.body["status"] # => "pending"
# 2. Handle the callback (Sinatra example)
post "/webhooks/scan-complete" do
result = JSON.parse(request.body.read)
if result["status"] == "found"
# quarantine or delete the file
end
content_type :json
{ received: true }.to_json
end
Or poll for results instead:
# Poll for results (alternative to callback)
result = conn.get("/v1.0/scans/#{scan_id}")
puts result.body["status"] # => "ok", "found", "pending", etc.
Sinatra
A Sinatra app that accepts file uploads and scans them:
require "sinatra"
require "faraday"
require "faraday/multipart"
require "json"
SCANNER_URL = ENV.fetch("ATTACHMENT_SCANNER_URL")
API_TOKEN = ENV.fetch("ATTACHMENT_SCANNER_API_TOKEN")
def scanner_connection(type)
Faraday.new(SCANNER_URL) do |f|
f.request :authorization, "Bearer", API_TOKEN
f.request type
f.response :json
end
end
# Scan by URL
post "/scan/url" do
body = JSON.parse(request.body.read)
response = scanner_connection(:json).post("/v1.0/scans") do |req|
req.body = { url: body["url"] }
end
content_type :json
response.body.to_json
end
# Scan by file upload
post "/scan/file" do
file = params[:file]
response = scanner_connection(:multipart).post("/v1.0/scans") do |req|
req.body = {
file: Faraday::Multipart::FilePart.new(
file[:tempfile], file[:type], file[:filename]
)
}
end
content_type :json
response.body.to_json
end
# Webhook callback handler
post "/webhooks/scan-complete" do
result = JSON.parse(request.body.read)
if result["status"] == "found"
# quarantine or delete the file
elsif result["status"] == "ok"
# file is clean — move to final storage
end
content_type :json
{ received: true }.to_json
end
Rails
require "faraday"
require "faraday/multipart"
class ScansController < ActionController::API
def scan_url
conn = scanner_connection(:json)
response = conn.post("/v1.0/scans") do |req|
req.body = { url: params[:url] }
end
render json: response.body
end
def scan_file
uploaded = params[:file]
conn = scanner_connection(:multipart)
response = conn.post("/v1.0/scans") do |req|
req.body = {
file: Faraday::Multipart::FilePart.new(
uploaded.tempfile,
uploaded.content_type,
uploaded.original_filename
)
}
end
render json: response.body
end
# Webhook callback handler
def scan_callback
if params[:status] == "found"
# quarantine or delete the file
elsif params[:status] == "ok"
# file is clean — move to final storage
end
render json: { received: true }
end
private
def scanner_connection(type)
Faraday.new(ENV.fetch("ATTACHMENT_SCANNER_URL")) do |f|
f.request :authorization, "Bearer", ENV.fetch("ATTACHMENT_SCANNER_API_TOKEN")
f.request type
f.response :json
end
end
end
curl Equivalent
# Scan by URL
curl -X POST https://YOUR_SCANNER_URL/v1.0/scans \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"url": "https://www.attachmentscanner.com/eicar.com"}'
# Scan by file upload
curl -X POST https://YOUR_SCANNER_URL/v1.0/scans \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-F "file=@/path/to/file.pdf"
# Async scan with callback
curl -X POST https://YOUR_SCANNER_URL/v1.0/scans \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/file.zip", "async": true, "callback": "https://your-app.com/webhooks/scan-complete"}'