1
mirror of https://github.com/rapid7/metasploit-framework synced 2024-08-28 23:26:18 +02:00

Use rex-mime gem

MS-1710
This commit is contained in:
dmohanty-r7 2016-09-01 11:38:07 -05:00
parent 8b9661d8e4
commit e36cfa54b1
No known key found for this signature in database
GPG Key ID: D1B3982EAB38742F
12 changed files with 10 additions and 989 deletions

View File

@ -35,6 +35,7 @@ PATH
redcarpet
rex-arch
rex-java
rex-mime
rex-ole
rex-powershell
rex-random_identifier
@ -180,7 +181,7 @@ GEM
multi_json (1.12.1)
multi_test (0.1.2)
multipart-post (2.0.0)
nessus_rest (0.1.3)
nessus_rest (0.1.4)
net-ssh (3.2.0)
network_interface (0.0.1)
nokogiri (1.6.8)
@ -224,15 +225,17 @@ GEM
thor (>= 0.18.1, < 2.0)
rake (11.2.2)
rb-readline-r7 (0.5.2.0)
recog (2.0.21)
recog (2.0.22)
nokogiri
redcarpet (3.3.4)
rex-arch (0.1.1)
rex-text
rex-java (0.1.2)
rex-mime (0.1.1)
rex-text
rex-ole (0.1.2)
rex-text
rex-powershell (0.1.1)
rex-powershell (0.1.64)
rex-random_identifier
rex-text
rex-random_identifier (0.1.0)

View File

@ -57,6 +57,8 @@ require 'rex/java'
require 'rex/struct2'
# Library for working with OLE
require 'rex/ole'
# Library for creating and/or parsing MIME messages
require 'rex/mime'
# Generic classes
require 'rex/exceptions'

View File

@ -1,10 +0,0 @@
# -*- coding: binary -*-
module Rex
module MIME
require 'rex/mime/header'
require 'rex/mime/part'
require 'rex/mime/message'
end
end

View File

@ -1,17 +0,0 @@
# -*- coding: binary -*-
module Rex
module MIME
# Set of helpers methods to deal with SMTP encoding related topics.
module Encoding
# Enforces CRLF on the input data
#
# @param data [String] The data to CRLF enforce.
# @return [String] CRLF enforced data.
def force_crlf(data)
data.gsub("\r", '').gsub("\n", "\r\n")
end
end
end
end

View File

@ -1,79 +0,0 @@
# -*- coding: binary -*-
module Rex
module MIME
class Header
require 'rex/text'
attr_accessor :headers
def initialize(data='')
self.headers = []
parse(data)
end
def parse(data)
prev = nil
data.gsub("\r", '').split("\n").each do |line|
# Handle header folding
if (line =~ /^\s+/)
# Ignore if there is no previous header
next if not prev
next if not self.headers[prev]
self.headers[prev][1] << line.strip
next
end
var, val = line.split(':', 2)
next if val.nil?
self.headers << [ var.to_s.strip, val.to_s.strip ]
prev = self.headers.length - 1
end
end
def to_s
self.headers.map{ |pair| "#{pair[0]}: #{pair[1]}\r\n" }.join
end
def find(idx)
if (idx.class == ::Fixnum)
return self.headers[idx]
else
self.headers.each do |pair|
if (pair[0] == idx.to_s)
return pair
end
end
end
nil
end
def set(var, val)
hdr = self.find(var) || self.add(var, '')
hdr[1] = val
end
def add(var, val)
self.headers << [var, val]
self.headers[-1]
end
def remove(idx)
if (idx.class == ::Fixnum)
self.headers.delete_at(idx)
else
self.headers.each_index do |i|
pair = self.headers[i]
if (pair[0] == idx.to_s)
self.headers.delete_at(i)
end
end
end
end
end
end
end

View File

@ -1,144 +0,0 @@
# -*- coding: binary -*-
module Rex
module MIME
class Message
require 'rex/mime/header'
require 'rex/mime/part'
require 'rex/mime/encoding'
require 'rex/text'
include Rex::MIME::Encoding
attr_accessor :header, :parts, :bound, :content
def initialize(data=nil)
self.header = Rex::MIME::Header.new
self.parts = []
self.bound = "_Part_#{rand(1024)}_#{rand(0xffffffff)}_#{rand(0xffffffff)}"
self.content = ''
if data
head,body = data.split(/\r?\n\r?\n/, 2)
self.header.parse(head)
ctype = self.header.find('Content-Type')
if ctype && ctype[1] && ctype[1] =~ /multipart\/mixed;\s*boundary="?([A-Za-z0-9'\(\)\+\_,\-\.\/:=\?^\s]+)"?/
self.bound = $1
chunks = body.to_s.split(/--#{self.bound}(--)?\r?\n/)
self.content = chunks.shift.to_s.gsub(/\s+$/, '')
self.content << "\r\n" unless self.content.empty?
chunks.each do |chunk|
break if chunk == "--"
head,body = chunk.split(/\r?\n\r?\n/, 2)
part = Rex::MIME::Part.new
part.header.parse(head)
part.content = body.gsub(/\s+$/, '')
self.parts << part
end
else
self.content = body.to_s.gsub(/\s+$/, '') + "\r\n"
end
end
end
def to
(self.header.find('To') || [nil, nil])[1]
end
def to=(val)
self.header.set("To", val)
end
def from=(val)
self.header.set("From", val)
end
def from
(self.header.find('From') || [nil, nil])[1]
end
def subject=(val)
self.header.set("Subject", val)
end
def subject
(self.header.find('Subject') || [nil, nil])[1]
end
def mime_defaults
self.header.set("MIME-Version", "1.0")
self.header.set("Content-Type", "multipart/mixed; boundary=\"#{self.bound}\"")
self.header.set("Subject", '') # placeholder
self.header.set("Date", Time.now.strftime("%a,%e %b %Y %H:%M:%S %z"))
self.header.set("Message-ID",
"<"+
Rex::Text.rand_text_alphanumeric(rand(20)+40)+
"@"+
Rex::Text.rand_text_alpha(rand(20)+3)+
">"
)
self.header.set("From", '') # placeholder
self.header.set("To", '') # placeholder
end
def add_part(data='', content_type='text/plain', transfer_encoding="8bit", content_disposition=nil)
part = Rex::MIME::Part.new
if content_disposition
part.header.set("Content-Disposition", content_disposition)
end
part.header.set("Content-Type", content_type) if content_type
if transfer_encoding
part.header.set("Content-Transfer-Encoding", transfer_encoding)
end
part.content = data
self.parts << part
part
end
def add_part_attachment(data, name)
self.add_part(
Rex::Text.encode_base64(data, "\r\n"),
"application/octet-stream; name=\"#{name}\"",
"base64",
"attachment; filename=\"#{name}\""
)
end
def add_part_inline_attachment(data, name)
self.add_part(
Rex::Text.encode_base64(data, "\r\n"),
"application/octet-stream; name=\"#{name}\"",
"base64",
"inline; filename=\"#{name}\""
)
end
def to_s
header_string = self.header.to_s
msg = header_string.empty? ? '' : force_crlf(self.header.to_s + "\r\n")
msg << force_crlf(self.content + "\r\n") unless self.content.to_s.strip.empty?
self.parts.each do |part|
msg << force_crlf("--" + self.bound + "\r\n")
msg << part.to_s
end
msg << force_crlf("--" + self.bound + "--\r\n") if self.parts.length > 0
msg
end
end
end
end

View File

@ -1,50 +0,0 @@
# -*- coding: binary -*-
module Rex
module MIME
class Part
require 'rex/mime/header'
require 'rex/mime/encoding'
include Rex::MIME::Encoding
attr_accessor :header, :content
def initialize
self.header = Rex::MIME::Header.new
self.content = ''
end
def to_s
self.header.to_s + "\r\n" + content_encoded + "\r\n"
end
# Returns the part content with any necessary encoding or transformation
# applied.
#
# @return [String] Content with encoding or transformations applied.
def content_encoded
binary_content? ? content : force_crlf(content)
end
# Answers if the part content is binary.
#
# @return [Boolean] true if the part content is binary, false otherwise.
def binary_content?
transfer_encoding && transfer_encoding == 'binary'
end
# Returns the Content-Transfer-Encoding of the part.
#
# @return [nil] if the part hasn't Content-Transfer-Encoding.
# @return [String] The Content-Transfer-Encoding or the part.
def transfer_encoding
h = header.find('Content-Transfer-Encoding')
return nil if h.nil?
h[1]
end
end
end
end

View File

@ -132,6 +132,8 @@ Gem::Specification.new do |spec|
spec.add_runtime_dependency 'rex-arch'
# Library for working with OLE.
spec.add_runtime_dependency 'rex-ole'
# Library for creating and/or parsing MIME messages.
spec.add_runtime_dependency 'rex-mime'
# rb-readline doesn't work with Ruby Installer due to error with Fiddle:
# NoMethodError undefined method `dlopen' for Fiddle:Module

View File

@ -1,32 +0,0 @@
# -*- coding:binary -*-
require 'spec_helper'
require 'rex/mime'
RSpec.describe Rex::MIME::Encoding do
subject do
mod = Class.new
mod.extend described_class
mod
end
describe "#force_crlf" do
it "deletes \\r characters" do
expect(subject.force_crlf("Test\r1\r")).to_not include("\\r")
end
it "substitutes \\n characters by \\r\\n sequences" do
expect(subject.force_crlf("Test 2\n")).to end_with("\r\n")
end
it "preserves \r\n sequences" do
expect(subject.force_crlf("\r\nTest 3\r\n")).to eq("\r\nTest 3\r\n")
end
it "first deletes \\r characters, then substitutes \\n characters" do
expect(subject.force_crlf("\rTest 4\r\n\r\r\n")).to eq("Test 4\r\n\r\n")
end
end
end

View File

@ -1,151 +0,0 @@
# -*- coding:binary -*-
require 'spec_helper'
require 'rex/mime'
RSpec.describe Rex::MIME::Header do
let(:mime_headers_test) do
<<-EOS
Content-Type: text/plain;
Content-Disposition: attachment; filename="test.txt"
EOS
end
subject do
described_class.new
end
describe "#initialize" do
subject(:header_class) do
described_class.allocate
end
it "returns an Array" do
expect(header_class.send(:initialize)).to be_a(Array)
end
it "creates an empty headers array by default" do
expect(header_class.send(:initialize)).to be_empty
end
it "populates headers array with data from argument" do
header_class.send(:initialize, mime_headers_test)
expect(header_class.headers.length).to be(2)
end
end
describe "#add" do
it "returns the added entry" do
expect(subject.add('var', 'val')).to eq(['var', 'val'])
end
it "adds a new entry into the headers array" do
subject.add('var', 'val')
expect(subject.headers.length).to eq(1)
end
end
describe "#set" do
it "returns the set value" do
expect(subject.set('var', 'val')).to eq('val')
end
it "modifies the header entry if it exists" do
subject.add('var', 'val')
subject.set('var', 'val2')
expect(subject.headers.length).to eq(1)
expect(subject.headers[0]).to eq(['var', 'val2'])
end
it "creates the header entry if doesn't exist" do
subject.set('var2', 'val2')
expect(subject.headers.length).to eq(1)
expect(subject.headers[0]).to eq(['var2', 'val2'])
end
end
describe "#remove" do
it "doesn't remove any header if index doesn't exist" do
subject.add('var', 'val')
subject.remove(10000)
expect(subject.headers.length).to eq(1)
end
it "doesn't remove any header if var name doesn't exist" do
subject.add('var', 'val')
subject.remove('var2')
expect(subject.headers.length).to eq(1)
end
it "removes header entry if index exists" do
subject.add('var', 'val')
subject.remove(0)
expect(subject.headers.length).to eq(0)
end
it "removes any header entry with var name" do
subject.add('var', 'val')
subject.add('var2', 'val2')
subject.add('var', 'val3')
subject.remove('var')
expect(subject.headers.length).to eq(1)
end
end
describe "#find" do
it "returns nil if header index doesn't exist" do
expect(subject.find(1)).to be_nil
end
it "returns nil if header var name doesn't exist" do
expect(subject.find('var')).to be_nil
end
it "returns the header at index if exists" do
subject.add('var', 'val')
expect(subject.find(0)).to eq(['var', 'val'])
end
it "returns the first header with var name if exists" do
subject.add('var', 'val')
subject.add('var', 'val2')
subject.add('var', 'val3')
expect(subject.find('var')).to eq(['var', 'val'])
end
end
describe "#to_s" do
it "returns empty String if there aren't headers" do
expect(subject.to_s).to be_empty
end
it "returns string with headers separated by \\r\\n sequences" do
subject.add('var', 'val')
subject.add('var', 'val2')
subject.add('var3', 'val3')
expect(subject.to_s).to eq("var: val\r\nvar: val2\r\nvar3: val3\r\n")
end
end
describe "#parse" do
let(:complex_header) do
'Date: Wed,20 Aug 2014 08:45:38 -0500'
end
it "parses headers separated by lines" do
subject.parse(mime_headers_test)
expect(subject.headers.length).to eq(2)
end
it "parses headers names and values separated by :" do
subject.parse(mime_headers_test)
expect(subject.headers).to eq([['Content-Type', 'text/plain;'], ['Content-Disposition', 'attachment; filename="test.txt"']])
end
it "parses headers with ':' characters in the value" do
subject.parse(complex_header)
expect(subject.headers).to eq([['Date', 'Wed,20 Aug 2014 08:45:38 -0500']])
end
end
end

View File

@ -1,411 +0,0 @@
# -*- coding:binary -*-
require 'spec_helper'
require 'rex/mime'
require 'rex/text'
RSpec.describe Rex::MIME::Message do
subject do
described_class.new
end
describe "#initialize" do
subject(:message_class) do
described_class.allocate
end
let(:raw_message) do
message = "MIME-Version: 1.0\r\n"
message << "Content-Type: multipart/mixed; boundary=\"_Part_12_3195573780_381739540\"\r\n"
message << "Subject: Pull Request\r\n"
message << "Date: Wed,20 Aug 2014 08:45:38 -0500\r\n"
message << "Message-ID: <WRobqc7gEyQVIQwEkLS7FN3ZNhS1Xj9pU2szC24rggMg@tqUqGjjSLEvssbwm>\r\n"
message << "From: contributor@msfdev.int\r\n"
message << "To: msfdev@msfdev.int\r\n"
message << "\r\n"
message << "--_Part_12_3195573780_381739540\r\n"
message << "Content-Disposition: inline; filename=\"content\"\r\n"
message << "Content-Type: application/octet-stream; name=\"content\"\r\n"
message << "Content-Transfer-Encoding: base64\r\n"
message << "\r\n"
message << "Q29udGVudHM=\r\n"
message << "\r\n"
message << "--_Part_12_3195573780_381739540--\r\n"
message
end
it "creates a new Rex::MIME::Header" do
message_class.send(:initialize)
expect(message_class.header).to be_a(Rex::MIME::Header)
end
it "creates an empty array of parts" do
message_class.send(:initialize)
expect(message_class.parts).to be_empty
end
it "creates a random bound" do
message_class.send(:initialize)
expect(message_class.bound).to include('_Part_')
end
it "allows to populate headers from argument" do
message_class.send(:initialize, raw_message)
expect(message_class.header.headers.length).to eq(7)
end
it "allows to create a MIME-Version header from argument" do
message_class.send(:initialize, raw_message)
expect(message_class.header.find('MIME-Version')).to eq(['MIME-Version', '1.0'])
end
it "allows to create a Content-Type header from argument" do
message_class.send(:initialize, raw_message)
expect(message_class.header.find('Content-Type')).to eq(['Content-Type', "multipart/mixed; boundary=\"_Part_12_3195573780_381739540\""])
end
it "allows to create a Subject header from argument" do
message_class.send(:initialize, raw_message)
expect(message_class.header.find('Subject')).to eq(['Subject', 'Pull Request'])
end
it "allows to create a Date header from argument" do
message_class.send(:initialize, raw_message)
expect(message_class.header.find('Date')).to eq(['Date', 'Wed,20 Aug 2014 08:45:38 -0500'])
end
it "allows to create a Message-ID header from argument" do
message_class.send(:initialize, raw_message)
expect(message_class.header.find('Message-ID')).to eq(['Message-ID', '<WRobqc7gEyQVIQwEkLS7FN3ZNhS1Xj9pU2szC24rggMg@tqUqGjjSLEvssbwm>'])
end
it "allows to create a From header from argument" do
message_class.send(:initialize, raw_message)
expect(message_class.header.find('From')).to eq(['From', 'contributor@msfdev.int'])
end
it "allows to create a To header from argument" do
message_class.send(:initialize, raw_message)
expect(message_class.header.find('To')).to eq(['To', 'msfdev@msfdev.int'])
end
it "allows to populate parts from argument" do
message_class.send(:initialize, raw_message)
expect(message_class.parts.length).to eq(1)
end
it "allows to populate parts headers from argument" do
message_class.send(:initialize, raw_message)
part = message_class.parts[0]
expect(part.header.headers.length).to eq(3)
end
it "allows to populate parts contents from argument" do
message_class.send(:initialize, raw_message)
part = message_class.parts[0]
expect(part.content).to eq("Q29udGVudHM=")
end
end
describe "#to" do
it "returns nil if To: header doesn't exist" do
expect(subject.to).to be_nil
end
it "returns the To: header value if it exists" do
subject.header.add('To', 'msfdev')
expect(subject.to).to eq('msfdev')
end
end
describe "#to=" do
it "sets the To: header value" do
subject.to = 'msfdev'
expect(subject.to).to eq('msfdev')
end
end
describe "#from" do
it "returns nil if From: header doesn't exist" do
expect(subject.from).to be_nil
end
it "returns the From: header value if it exists" do
subject.header.add('From', 'msfdev')
expect(subject.from).to eq('msfdev')
end
end
describe "#from=" do
it "sets the From: header value" do
subject.from = 'msfdev'
expect(subject.from).to eq('msfdev')
end
end
describe "#subject" do
it "returns nil if Subject: header doesn't exist" do
expect(subject.subject).to be_nil
end
it "returns the Subject: header value if it exists" do
subject.header.add('Subject', 'msfdev')
expect(subject.subject).to eq('msfdev')
end
end
describe "#subject=" do
it "sets the Subject: header value" do
subject.subject = 'msfdev'
expect(subject.subject).to eq('msfdev')
end
end
describe "#mime_defaults" do
it "sets the MIME-Version header" do
subject.mime_defaults
expect(subject.header.find('MIME-Version')).to_not be_nil
end
it "sets the MIME-Version header to '1.0'" do
subject.mime_defaults
expect(subject.header.find('MIME-Version')).to eq(['MIME-Version', '1.0'])
end
it "sets the Content-Type header" do
subject.mime_defaults
expect(subject.header.find('Content-Type')).to_not be_nil
end
it "sets the Content-Type header to multipart/mixed" do
subject.mime_defaults
expect(subject.header.find('Content-Type')[1]).to include('multipart/mixed')
end
it "sets the Subject header" do
subject.mime_defaults
expect(subject.header.find('Subject')).to_not be_nil
end
it "sets the Subject header to empty string" do
subject.mime_defaults
expect(subject.header.find('Subject')).to eq(['Subject', ''])
end
it "sets the Message-ID header" do
subject.mime_defaults
expect(subject.header.find('Message-ID')).to_not be_nil
end
it "sets the From header" do
subject.mime_defaults
expect(subject.header.find('From')).to_not be_nil
end
it "sets the From header to empty string" do
subject.mime_defaults
expect(subject.header.find('From')).to eq(['From', ''])
end
it "sets the To header" do
subject.mime_defaults
expect(subject.header.find('To')).to_not be_nil
end
it "sets the To header to empty string" do
subject.mime_defaults
expect(subject.header.find('To')).to eq(['To', ''])
end
end
describe "#add_part" do
subject(:part) do
described_class.new.add_part(*args)
end
let(:args) { [] }
it "returns the new part" do
expect(part).to be_a(Rex::MIME::Part)
end
it "set part's Content-Type to text/plain by default" do
expect(part.header.find('Content-Type')[1]).to eq('text/plain')
end
it "set part's Content-Transfer-Encoding to 8bit by default" do
expect(part.header.find('Content-Transfer-Encoding')[1]).to eq('8bit')
end
it "doesn't set part's Content-Disposition by default" do
expect(part.header.find('Content-Disposition')).to be_nil
end
context "with Content-Type argument" do
let(:args) { ['', 'application/pdf'] }
it "creates a part Content-Type header" do
expect(part.header.find('Content-Type')[1]).to eq('application/pdf')
end
end
context "with Content-Transfer-Encoding argument" do
let(:args) { ['', 'application/pdf', 'binary'] }
it "creates a part Content-Transfer-Encoding header" do
expect(part.header.find('Content-Transfer-Encoding')[1]).to eq('binary')
end
end
context "with Content-Disposition argument" do
let(:args) { ['', 'application/pdf', 'binary', 'attachment; filename="fname.ext"'] }
it "creates a part Content-Disposition header" do
expect(part.header.find('Content-Disposition')[1]).to eq('attachment; filename="fname.ext"')
end
end
context "with content argument" do
let(:args) { ['msfdev'] }
it "creates part content" do
expect(part.content).to eq('msfdev')
end
end
end
describe "#add_part_attachment" do
it "requires data argument" do
expect { subject.add_part_attachment }.to raise_error(ArgumentError)
end
it "requires name argument" do
expect { subject.add_part_attachment('data') }.to raise_error(ArgumentError)
end
it 'returns the new Rex::MIME::Part' do
expect(subject.add_part_attachment('data', 'name')).to be_a(Rex::MIME::Part)
end
it 'encodes the part content with base64' do
part = subject.add_part_attachment('data', 'name')
expect(part.content).to eq(Rex::Text.encode_base64('data', "\r\n"))
end
it 'setup Content-Type as application/octet-stream' do
part = subject.add_part_attachment('data', 'name')
expect(part.header.find('Content-Type')[1]).to eq('application/octet-stream; name="name"')
end
it 'setup Content-Transfer-Encoding as base64' do
part = subject.add_part_attachment('data', 'name')
expect(part.header.find('Content-Transfer-Encoding')[1]).to eq('base64')
end
it 'setup Content-Disposition as attachment' do
part = subject.add_part_attachment('data', 'name')
expect(part.header.find('Content-Disposition')[1]).to eq('attachment; filename="name"')
end
end
describe "#add_part_inline_attachment" do
it "requires data argument" do
expect { subject.add_part_inline_attachment }.to raise_error(ArgumentError)
end
it "requires name argument" do
expect { subject.add_part_inline_attachment('data') }.to raise_error(ArgumentError)
end
it 'returns the new Rex::MIME::Part' do
expect(subject.add_part_inline_attachment('data', 'name')).to be_a(Rex::MIME::Part)
end
it 'encodes the part content with base64' do
part = subject.add_part_inline_attachment('data', 'name')
expect(part.content).to eq(Rex::Text.encode_base64('data', "\r\n"))
end
it 'setup Content-Type as application/octet-stream' do
part = subject.add_part_inline_attachment('data', 'name')
expect(part.header.find('Content-Type')[1]).to eq('application/octet-stream; name="name"')
end
it 'setup Content-Transfer-Encoding as base64' do
part = subject.add_part_inline_attachment('data', 'name')
expect(part.header.find('Content-Transfer-Encoding')[1]).to eq('base64')
end
it 'setup Content-Disposition as attachment' do
part = subject.add_part_inline_attachment('data', 'name')
expect(part.header.find('Content-Disposition')[1]).to eq('inline; filename="name"')
end
end
describe "#to_s" do
let(:regexp_mail) do
regex = "MIME-Version: 1.0\r\n"
regex << "Content-Type: multipart/mixed; boundary=\"_Part_.*\"\r\n"
regex << "Subject: Pull Request\r\n"
regex << "Date: .*\r\n"
regex << "Message-ID: <.*@.*>\r\n"
regex << "From: contributor@msfdev.int\r\n"
regex << "To: msfdev@msfdev.int\r\n"
regex << "\r\n"
regex << "--_Part_.*\r\n"
regex << "Content-Disposition: inline\r\n"
regex << "Content-Type: text/plain\r\n"
regex << "Content-Transfer-Encoding: base64\r\n"
regex << "\r\n"
regex << "Q29udGVudHM=\r\n"
regex << "\r\n"
regex << "--_Part_.*--\r\n"
Regexp.new(regex)
end
let(:regexp_web) do
regex = "--_Part_.*\r\n"
regex << "Content-Disposition: form-data; name=\"action\"\r\n"
regex << "\r\n"
regex << "save\r\n"
regex << "--_Part_.*\r\n"
regex << "Content-Disposition: form-data; name=\"file\"; filename=\"test.txt\"\r\n"
regex << "Content-Type: application/octet-stream\r\n"
regex << "\r\n"
regex << "Contents\r\n"
regex << "--_Part_.*\r\n"
regex << "Content-Disposition: form-data; name=\"title\"\r\n"
regex << "\r\n"
regex << "Title\r\n"
regex << "--_Part_.*--\r\n"
Regexp.new(regex)
end
it "returns empty string if Rex::MIME::Message is empty" do
expect(subject.to_s).to be_empty
end
it "generates valid MIME email messages" do
subject.mime_defaults
subject.from = "contributor@msfdev.int"
subject.to = "msfdev@msfdev.int"
subject.subject = "Pull Request"
subject.add_part(Rex::Text.encode_base64("Contents", "\r\n"), "text/plain", "base64", "inline")
expect(regexp_mail.match(subject.to_s)).to_not be_nil
end
it "generates valid MIME web forms" do
subject.add_part("save", nil, nil, "form-data; name=\"action\"")
subject.add_part("Contents", "application/octet-stream", nil, "form-data; name=\"file\"; filename=\"test.txt\"")
subject.add_part("Title", nil, nil, "form-data; name=\"title\"")
expect(regexp_web.match(subject.to_s)).to_not be_nil
end
end
end

View File

@ -1,92 +0,0 @@
# -*- coding:binary -*-
require 'spec_helper'
require 'rex/mime'
RSpec.describe Rex::MIME::Part do
subject do
described_class.new
end
describe "#initialize" do
subject(:part_class) do
described_class.allocate
end
it "initializes the Rex::MIME::Header object" do
part_class.send(:initialize)
expect(part_class.header).to be_a(Rex::MIME::Header)
end
it "initializes the Rex::MIME::Header with an empty array of headers" do
part_class.send(:initialize)
expect(part_class.header.headers).to be_empty
end
it "Initializes content with an empty String" do
part_class.send(:initialize)
expect(part_class.content).to be_empty
end
end
describe "#transfer_encoding" do
it "returns nil if the part hasn't a Content-Transfer-Encoding header" do
expect(subject.transfer_encoding).to be_nil
end
it "returns the transfer encoding value if a Content-Transfer-Encoding header exists" do
subject.header.add('Content-Transfer-Encoding', 'base64')
expect(subject.transfer_encoding).to eq('base64')
end
end
describe "#binary_content?" do
it "returns false if transfer encoding isn't defined" do
expect(subject.binary_content?).to be_falsey
end
it "returns false if transfer encoding isn't binary" do
subject.header.add('Content-Transfer-Encoding', 'base64')
expect(subject.binary_content?).to be_falsey
end
it "returns true if transfer encoding is binary" do
subject.header.add('Content-Transfer-Encoding', 'binary')
expect(subject.binary_content?).to be_truthy
end
end
describe "#content_encoded" do
let(:content_test) do
"\rTest1\n"
end
it "returns the exact content if transfer encoding is binary" do
subject.header.add('Content-Transfer-Encoding', 'binary')
subject.content = content_test
expect(subject.content_encoded).to eq(content_test)
end
it "returns the content crlf encoded if transfer encoding isn't binary" do
subject.content = content_test
expect(subject.content_encoded).to eq("Test1\r\n")
end
end
describe "#to_s" do
it "returns headers and content separated by two \\r\\n sequences" do
subject.header.add('var', 'val')
subject.content = 'content'
expect(subject.to_s).to eq("var: val\r\n\r\ncontent\r\n")
end
it "returns two \\r\\n sequences if part is empty" do
expect(subject.to_s).to eq("\r\n\r\n")
end
it "ends with \\r\\n sequence" do
expect(subject.to_s).to end_with("\r\n")
end
end
end