class Schleuder::List
Public Class Methods
by_recipient(recipient)
click to toggle source
# File lib/schleuder/list.rb, line 223 def self.by_recipient(recipient) listname = recipient.gsub(/-(sendkey|request|owner|bounce)@/, '@') where(email: listname).first end
configurable_attributes()
click to toggle source
# File lib/schleuder/list.rb, line 89 def self.configurable_attributes @configurable_attributes ||= begin all = self.validators.map(&:attributes).flatten.uniq.compact.sort all - [:email, :fingerprint] end end
listdir(listname)
click to toggle source
# File lib/schleuder/list.rb, line 274 def self.listdir(listname) File.join( Conf.lists_dir, listname.split('@').reverse ) end
Public Instance Methods
admin_only?(keyword)
click to toggle source
# File lib/schleuder/list.rb, line 333 def admin_only?(keyword) keywords_admin_only.include?(keyword) end
admins()
click to toggle source
# File lib/schleuder/list.rb, line 108 def admins subscriptions.where(admin: true) end
bounce_address()
click to toggle source
# File lib/schleuder/list.rb, line 240 def bounce_address @bounce_address ||= email.gsub('@', '-bounce@') end
check_keys()
click to toggle source
# File lib/schleuder/list.rb, line 162 def check_keys now = Time.now checkdate = now + (60 * 60 * 24 * 14) # two weeks unusable = [] expiring = [] keys.each do |key| expiry = key.subkeys.first.expires if expiry && expiry > now && expiry < checkdate # key expires in the near future expdays = ((expiry - now)/86400).to_i expiring << [key, expdays] end if ! key.usable? unusable << [key, key.usability_issue] end end text = '' expiring.each do |key, days| text << I18n.t('key_expires', days: days, key_summary: key.summary ) text << "\n" end unusable.each do |key, usability_issue| text << I18n.t('key_unusable', usability_issue: usability_issue, key_summary: key.summary ) text << "\n" end text end
cleanup()
click to toggle source
TODO: place this somewhere sensible. Call cleanup when script finishes.
Signal.trap(0, proc { @list.cleanup })
# File lib/schleuder/list.rb, line 256 def cleanup if @gpg_agent_pid Process.kill('TERM', @gpg_agent_pid.to_i) end rescue => e $stderr.puts "Failed to kill gpg-agent: #{e}" end
delete_key(fingerprint)
click to toggle source
# File lib/schleuder/list.rb, line 135 def delete_key(fingerprint) if key = keys(fingerprint).first key.delete! true else false end end
export_key(fingerprint=self.fingerprint)
click to toggle source
# File lib/schleuder/list.rb, line 144 def export_key(fingerprint=self.fingerprint) key = keys(fingerprint).first if key.blank? return false end key.armored end
fetch_keys(input)
click to toggle source
# File lib/schleuder/list.rb, line 215 def fetch_keys(input) key_fetcher.fetch(input) end
fingerprint=(arg)
click to toggle source
# File lib/schleuder/list.rb, line 268 def fingerprint=(arg) if arg write_attribute(:fingerprint, arg.gsub(/\s*/, '').gsub(/^0x/, '').chomp.upcase) end end
from_admin?(mail)
click to toggle source
# File lib/schleuder/list.rb, line 337 def from_admin?(mail) return false if ! mail.was_validly_signed? admins.find do |admin| admin.fingerprint == mail.signing_key.fingerprint end.presence || false end
gpg()
click to toggle source
# File lib/schleuder/list.rb, line 244 def gpg @gpg_ctx ||= begin # TODO: figure out why set it again... # Set GNUPGHOME when list is created. set_gnupg_home GPGME::Ctx.new armor: true end end
gpg_sign_options()
click to toggle source
# File lib/schleuder/list.rb, line 264 def gpg_sign_options {sign: true, sign_as: self.fingerprint} end
import_key(importable)
click to toggle source
# File lib/schleuder/list.rb, line 124 def import_key(importable) gpg.keyimport(importable) end
import_key_and_find_fingerprint(key_material)
click to toggle source
# File lib/schleuder/list.rb, line 128 def import_key_and_find_fingerprint(key_material) return nil if key_material.blank? import_result = import_key(key_material) gpg.interpret_import_result(import_result) end
key(fingerprint=self.fingerprint)
click to toggle source
# File lib/schleuder/list.rb, line 112 def key(fingerprint=self.fingerprint) keys(fingerprint).first end
key_fetcher()
click to toggle source
# File lib/schleuder/list.rb, line 219 def key_fetcher @key_fetcher ||= KeyFetcher.new(self) end
key_minimal_base64_encoded(fingerprint=self.fingerprint)
click to toggle source
# File lib/schleuder/list.rb, line 152 def key_minimal_base64_encoded(fingerprint=self.fingerprint) key = keys(fingerprint).first if key.blank? return false end Base64.strict_encode64(key.minimal) end
keys(identifier=nil, secret_only=nil)
click to toggle source
# File lib/schleuder/list.rb, line 120 def keys(identifier=nil, secret_only=nil) gpg.find_keys(identifier, secret_only) end
keywords_admin_notify()
click to toggle source
# File lib/schleuder/list.rb, line 325 def keywords_admin_notify Array(read_attribute(:keywords_admin_notify)) end
keywords_admin_only()
click to toggle source
# File lib/schleuder/list.rb, line 329 def keywords_admin_only Array(read_attribute(:keywords_admin_only)) end
listdir()
click to toggle source
# File lib/schleuder/list.rb, line 281 def listdir @listdir ||= self.class.listdir(self.email) end
logfile()
click to toggle source
# File lib/schleuder/list.rb, line 96 def logfile @logfile ||= File.join(Conf.listlogs_dir, self.email.split('@').reverse, 'list.log') end
logger()
click to toggle source
# File lib/schleuder/list.rb, line 100 def logger @logger ||= Listlogger.new(self) end
owner_address()
click to toggle source
# File lib/schleuder/list.rb, line 236 def owner_address @owner_address ||= email.gsub('@', '-owner@') end
refresh_keys()
click to toggle source
# File lib/schleuder/list.rb, line 200 def refresh_keys # reorder keys so the update pattern is random output = self.keys.shuffle.map do |key| # Sleep a short while to make traffic analysis less easy. sleep rand(1.0..5.0) key_fetcher.fetch(key.fingerprint, 'key_updated').presence end # Filter out some "noise" (if a key was unchanged, it wasn't really updated, was it?) # It would be nice to prevent these "false" lines in the first place, but I don't know how. output.reject! do |line| line.match('updated \(unchanged\)') end output.compact.join("\n") end
request_address()
click to toggle source
# File lib/schleuder/list.rb, line 232 def request_address @request_address ||= email.gsub('@', '-request@') end
secret_key()
click to toggle source
# File lib/schleuder/list.rb, line 116 def secret_key keys(self.fingerprint, true).first end
send_list_key_to_subscriptions()
click to toggle source
# File lib/schleuder/list.rb, line 348 def send_list_key_to_subscriptions mail = Mail.new mail.from = self.email mail.subject = I18n.t('list_public_key_subject') mail.body = I18n.t('list_public_key_attached') mail.attach_list_key!(self) send_to_subscriptions(mail) true end
send_to_subscriptions(mail, incoming_mail=nil)
click to toggle source
# File lib/schleuder/list.rb, line 358 def send_to_subscriptions(mail, incoming_mail=nil) logger.debug 'Sending to subscriptions.' mail.add_internal_footer! self.subscriptions.each do |subscription| begin if ! subscription.delivery_enabled logger.info "Not sending to #{subscription.email}: delivery is disabled." next end if ! self.deliver_selfsent && incoming_mail&.was_validly_signed? && ( subscription == incoming_mail&.signer ) logger.info "Not sending to #{subscription.email}: delivery of self sent is disabled." next end subscription.send_mail(mail, incoming_mail) rescue => exc msg = I18n.t('errors.delivery_error', { email: subscription.email, error: exc.to_s }) logger.error msg logger.error exc end end end
sendkey_address()
click to toggle source
# File lib/schleuder/list.rb, line 228 def sendkey_address @sendkey_address ||= email.gsub('@', '-sendkey@') end
set_attribute(attrib, value)
click to toggle source
# File lib/schleuder/list.rb, line 344 def set_attribute(attrib, value) self.send("#{attrib}=", value) end
subscribe(email, fingerprint=nil, adminflag=nil, deliveryflag=nil, key_material=nil)
click to toggle source
A convenience-method to simplify other code.
# File lib/schleuder/list.rb, line 286 def subscribe(email, fingerprint=nil, adminflag=nil, deliveryflag=nil, key_material=nil) messages = nil args = { list_id: self.id, email: email } if key_material.present? fingerprint, messages = import_key_and_find_fingerprint(key_material) end args[:fingerprint] = fingerprint # ActiveRecord does not treat nil as falsy for boolean columns, so we # have to avoid that in order to not receive an invalid object. The # database will use the column's default-value if no value is being # given. (I'd rather not duplicate the defaults here.) if ! adminflag.nil? args[:admin] = adminflag end if ! deliveryflag.nil? args[:delivery_enabled] = deliveryflag end subscription = Subscription.create(args) [subscription, messages] end
to_s()
click to toggle source
# File lib/schleuder/list.rb, line 104 def to_s email end
unsubscribe(email, delete_key=false)
click to toggle source
# File lib/schleuder/list.rb, line 310 def unsubscribe(email, delete_key=false) sub = subscriptions.where(email: email).first if sub.blank? false end if ! sub.destroy return sub end if delete_key sub.delete_key end end
Private Instance Methods
delete_listdirs()
click to toggle source
# File lib/schleuder/list.rb, line 391 def delete_listdirs if File.exist?(self.listdir) FileUtils.rm_rf(self.listdir, secure: true) Schleuder.logger.info "Deleted #{self.listdir}" end # If listlogs_dir is different from lists_dir, the logfile still exists # and needs to be deleted, too. logfile_dir = File.dirname(self.logfile) if File.exist?(logfile_dir) FileUtils.rm_rf(logfile_dir, secure: true) Schleuder.logger.info "Deleted #{logfile_dir}" end true rescue => exc # Don't use list-logger here — if the list-dir isn't present we can't log to it! Schleuder.logger.error "Error while deleting listdir: #{exc}" return false end
set_gnupg_home()
click to toggle source
# File lib/schleuder/list.rb, line 387 def set_gnupg_home ENV['GNUPGHOME'] = listdir end