Module: PWN::Plugins::Pony

Defined in:
lib/pwn/plugins/pony.rb

Overview

This is a fork of the no-longer maintained 'pony' gem. This module's purpose is to exist until the necessary functionality can be integrated into PWN::Plugins::MailAgent

Constant Summary collapse

@@options =
{}
@@override_options =
{}
@@subject_prefix =
false
@@append_inputs =
false

Class Method Summary collapse

Class Method Details

.add_attachments(opts = {}) ⇒ Object

Method usage N/A



241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'lib/pwn/plugins/pony.rb', line 241

public_class_method def self.add_attachments(opts = {})
  mail = opts[:mail]
  attachments = opts[:attachments] ||= {}
  attachments.each do |name, body|
    name = name.gsub(/\s+/, ' ')

    # mime-types wants to send these as "quoted-printable"
    if name.match?('.xlsx')
      mail.attachments[name] = {
        content: Base64.strict_encode64(body),
        transfer_encoding: :base64
      }
    else
      mail.attachments[name] = body
    end
    mail.attachments[name].add_content_id("<#{name}@#{Socket.gethostname}>")
  end
end

.append_inputsObject

Method usage N/A



53
54
55
# File 'lib/pwn/plugins/pony.rb', line 53

public_class_method def self.append_inputs
  @@append_inputs = true
end

.authorsObject

Author(s)

0day Inc. [email protected]



269
270
271
272
273
# File 'lib/pwn/plugins/pony.rb', line 269

public_class_method def self.authors
  "AUTHOR(S):
    0day Inc. <[email protected]>
  "
end

.build_html_part(opts = {}) ⇒ Object

Method usage N/A



190
191
192
193
194
195
196
197
198
199
200
# File 'lib/pwn/plugins/pony.rb', line 190

public_class_method def self.build_html_part(opts = {})
  Mail::Part.new(content_type: 'text/html;charset=UTF-8') do
    content_transfer_encoding 'quoted-printable'
    body Mail::Encodings::QuotedPrintable.encode(opts[:html_body])
    if opts[:html_body_part_header] && opts[:html_body_part_header].is_a?(Hash)
      opts[:html_body_part_header].each do |k, v|
        header[k] = v
      end
    end
  end
end

.build_mail(opts = {}) ⇒ Object

Method usage N/A



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/pwn/plugins/pony.rb', line 136

public_class_method def self.build_mail(opts = {})
  mail = Mail.new do |m|
    opts[:date] ||= Time.now
    opts[:from] ||= 'pony@unknown'
    opts[:via_options] ||= {}

    opts.each do |k, v|
      next if non_standard_options.include?(k)

      m.send(k, v)
    end

    # Automatic handling of multipart messages in the underlying
    # mail library works pretty well for the most part, but in
    # the case where we have attachments AND text AND html bodies
    # we need to explicitly define a second multipart/alternative
    # boundary to encapsulate the body-parts within the
    # multipart/mixed boundary that will be created automatically.
    if opts[:attachments] && opts[:html_body] && opts[:body]
      part(content_type: 'multipart/alternative') do |p|
        p.html_part = build_html_part(opts)
        p.text_part = build_text_part(opts)
      end

    # Otherwise if there is more than one part we still need to
    # ensure that they are all declared to be separate.
    elsif opts[:html_body] || opts[:attachments]
      m.html_part = build_html_part(opts) if opts[:html_body]

      m.text_part = build_text_part(opts) if opts[:body]

    elsif opts[:body]
      # If all we have is a text body, we don't need to worry about parts.
      body opts[:body]
    end

    m.delivery_method opts[:via], opts[:via_options]
  end

  (opts[:headers] ||= {}).each do |key, value|
    mail[key] = value
  end

  add_attachments(mail: mail, attachments: opts[:attachments]) if opts[:attachments]

  mail.charset = opts[:charset] if opts[:charset] # charset must be set after setting content_type

  mail.text_part.charset = opts[:text_part_charset] if mail.multipart? && opts[:text_part_charset]
  set_content_type(mail: mail, user_content_type: opts[:content_type])
  mail
end

.build_text_part(opts = {}) ⇒ Object

Method usage N/A



204
205
206
207
208
209
210
211
212
213
214
# File 'lib/pwn/plugins/pony.rb', line 204

public_class_method def self.build_text_part(opts = {})
  Mail::Part.new(content_type: 'text/plain') do
    content_type opts[:charset] if opts[:charset]
    body opts[:body]
    if opts[:body_part_header] && opts[:body_part_header].is_a?(Hash)
      opts[:body_part_header].each do |k, v|
        header[k] = v
      end
    end
  end
end

.default_delivery_methodObject

Method usage N/A



95
96
97
# File 'lib/pwn/plugins/pony.rb', line 95

public_class_method def self.default_delivery_method
  File.executable?(sendmail_binary) ? :sendmail : :smtp
end

.helpObject

Display Usage for this Module



277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
# File 'lib/pwn/plugins/pony.rb', line 277

public_class_method def self.help
  puts "USAGE:
    # Default options can be set so that they dont have to be repeated
    #{self}.options

    # Method usage N/A
    #{self}.options

    # Method usage N/A
    #{self}.override_options

    # Method usage N/A
    #{self}.override_options

    # Method usage N/A
    #{self}.subject_prefix(
      value: 'optional - integer or string to pack/encode'
    )

    # Method usage N/A
    #{self}.append_inputs

    # Send an email
    #{self}.mail(
      body: 'optional - body value consumed by #mail',
      subject: 'optional - subject value consumed by #mail',
      to: 'required - to value consumed by #mail',
      via: 'optional - via value consumed by #mail',
      via_options: 'optional - via options value consumed by #mail'
    )

    # Method usage N/A
    #{self}.permissable_options

    # Method usage N/A
    #{self}.default_delivery_method

    # Method usage N/A
    #{self}.standard_options

    # Method usage N/A
    #{self}.non_standard_options

    # Method usage N/A
    #{self}.build_mail(
      date: 'optional - date value consumed by #build_mail',
      from: 'optional - sender account or address to bind as operator',
      via_options: 'optional - via options value consumed by #build_mail',
      attachments: 'optional - attachments value consumed by #build_mail',
      html_body: 'optional - html body value consumed by #build_mail (defaults to opts[:attachments])',
      body: 'optional - body value consumed by #build_mail',
      via: 'optional - via value consumed by #build_mail',
      headers: 'optional - headers value consumed by #build_mail',
      charset: 'optional - charset value consumed by #build_mail',
      text_part_charset: 'optional - text part charset value consumed by #build_mail',
      content_type: 'optional - content type value consumed by #build_mail'
    )

    # Method usage N/A
    #{self}.build_html_part(
      html_body: 'optional - html body value consumed by #build_html_part',
      html_body_part_header: 'optional - html body part header value consumed by #build_html_part'
    )

    # Method usage N/A
    #{self}.build_text_part(
      charset: 'optional - charset value consumed by #build_text_part',
      body: 'optional - body value consumed by #build_text_part',
      body_part_header: 'optional - body part header value consumed by #build_text_part'
    )

    # Method usage N/A
    #{self}.set_content_type(
      mail: 'optional - mail value consumed by #set_content_type',
      user_content_type: 'optional - user content type value consumed by #set_content_type'
    )

    # Method usage N/A
    #{self}.add_attachments(
      mail: 'optional - mail value consumed by #add_attachments',
      attachments: 'optional - attachments value consumed by #add_attachments'
    )

    # Method usage N/A
    #{self}.sendmail_binary

    # Print the AUTHOR(S) string for this module.
    #{self}.authors
  "
  constants.sort
end

.mail(opts = {}) ⇒ Object

Send an email Pony.mail(:to => '[email protected]', :from => '[email protected]', :subject => 'hi', :body => 'Hello there.') Pony.mail(:to => '[email protected]', :html_body => '

Hello there!

', :body => "In case you can't read html, Hello there.") Pony.mail(:to => '[email protected]', :cc => '[email protected]', :from => '[email protected]', :subject => 'hi', :body => 'Howsit!')

Raises:

  • (ArgumentError)


61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/pwn/plugins/pony.rb', line 61

public_class_method def self.mail(opts = {})
  opts[:body] = "#{opts[:body]}/n #{opts}" if @@append_inputs

  opts = @@options.merge opts
  opts = opts.merge @@override_options

  opts[:subject] = "#{@@subject_prefix}#{opts[:subject]}" if @@subject_prefix

  raise ArgumentError, ':to is required' unless opts[:to]

  opts[:via] = default_delivery_method unless opts.key?(:via)

  if opts.key?(:via) && opts[:via] == :sendmail
    opts[:via_options] ||= {}
    opts[:via_options][:location] ||= sendmail_binary
  end

  deliver(mail: build_mail(opts))
end

.non_standard_optionsObject

Method usage N/A



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/pwn/plugins/pony.rb', line 118

public_class_method def self.non_standard_options
  %i[
    attachments
    body
    charset
    enable_starttls_auto
    headers
    html_body
    text_part_charset
    via
    via_options
    body_part_header
    html_body_part_header
  ]
end

.optionsObject

Method usage N/A



29
30
31
# File 'lib/pwn/plugins/pony.rb', line 29

public_class_method def self.options
  @@options
end

.options=(value) ⇒ Object

Default options can be set so that they don't have to be repeated.

Pony.options = { :from => '[email protected]', :via => :smtp, :via_options => { :host => 'smtp.yourserver.com' } }
Pony.mail(:to => 'foo@bar') # Sends mail to foo@bar from [email protected] using smtp
Pony.mail(:from => '[email protected]', :to => 'foo@bar') # Sends mail to foo@bar from [email protected] using smtp


23
24
25
# File 'lib/pwn/plugins/pony.rb', line 23

public_class_method def self.options=(value)
  @@options = value
end

.override_optionsObject

Method usage N/A



41
42
43
# File 'lib/pwn/plugins/pony.rb', line 41

public_class_method def self.override_options
  @@override_options
end

.override_options=(value) ⇒ Object

Method usage N/A



35
36
37
# File 'lib/pwn/plugins/pony.rb', line 35

public_class_method def self.override_options=(value)
  @@override_options = value
end

.permissable_optionsObject

Method usage N/A



83
84
85
# File 'lib/pwn/plugins/pony.rb', line 83

public_class_method def self.permissable_options
  standard_options + non_standard_options
end

.sendmail_binaryObject

Method usage N/A



262
263
264
265
# File 'lib/pwn/plugins/pony.rb', line 262

public_class_method def self.sendmail_binary
  sendmail = `which sendmail`.chomp
  sendmail.empty? ? '/usr/sbin/sendmail' : sendmail
end

.set_content_type(opts = {}) ⇒ Object

Method usage N/A



218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/pwn/plugins/pony.rb', line 218

public_class_method def self.set_content_type(opts = {})
  mail = opts[:mail]
  user_content_type = opts[:user_content_type]
  params = mail.content_type_parameters || {}
  case params
  when user_content_type
    content_type = user_content_type
  when mail.has_attachments?
    if mail.attachments.detect(&:inline?)
      content_type = ['multipart', 'related', params]
    else
      content_type = ['multipart', 'mixed', params]
    end
  when mail.multipart?
    content_type = ['multipart', 'alternative', params]
  else
    content_type = false
  end
  mail.content_type = content_type if content_type
end

.standard_optionsObject

Method usage N/A



101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/pwn/plugins/pony.rb', line 101

public_class_method def self.standard_options
  %i[
    to
    cc
    bcc
    from
    subject
    content_type
    message_id
    sender
    reply_to
    smtp_envelope_to
  ]
end

.subject_prefix(opts = {}) ⇒ Object

Method usage N/A



47
48
49
# File 'lib/pwn/plugins/pony.rb', line 47

public_class_method def self.subject_prefix(opts = {})
  @@subject_prefix = opts[:value]
end