1
1
مراية لـ https://github.com/postalserver/postal.git تم المزامنة 2026-09-05 12:35:18 +00:00

style(rubocop): fix all safe auto correctable offenses

هذا الالتزام موجود في:
Charlie Smurthwaite
2023-03-16 15:50:53 +00:00
الأصل 02c93a4850
التزام fd289c46fd
204 ملفات معدلة مع 2611 إضافات و2486 حذوفات

80
Gemfile
عرض الملف

@@ -1,52 +1,52 @@
source 'https://rubygems.org'
gem 'rails', '= 5.2.8.1'
gem 'mysql2'
gem 'puma'
gem 'turbolinks', '~> 5'
gem 'haml'
gem 'nifty-utils'
gem 'nilify_blanks'
gem 'kaminari'
gem 'bcrypt'
gem 'foreman'
gem 'hashie'
gem 'authie', '~> 3.0'
gem 'dynamic_form'
gem 'changey'
gem 'mail', :git => 'https://github.com/mikel/mail.git', :branch => '2-7-stable'
gem 'autoprefixer-rails'
gem 'bunny'
gem 'secure_headers'
gem 'chronic'
gem 'basic_ssl'
gem 'clockwork'
gem 'encrypto_signo'
gem 'nio4r'
gem 'sentry-raven'
gem 'gelf'
gem 'moonrope'
gem 'jwt'
gem 'highline', :require => false
gem 'resolv', '~> 0.2.1'
gem 'dotenv-rails'
source "https://rubygems.org"
gem "authie", "~> 3.0"
gem "autoprefixer-rails"
gem "basic_ssl"
gem "bcrypt"
gem "bunny"
gem "changey"
gem "chronic"
gem "clockwork"
gem "dotenv-rails"
gem "dynamic_form"
gem "encrypto_signo"
gem "foreman"
gem "gelf"
gem "haml"
gem "hashie"
gem "highline", require: false
gem "jwt"
gem "kaminari"
gem "mail", git: "https://github.com/mikel/mail.git", branch: "2-7-stable"
gem "moonrope"
gem "mysql2"
gem "nifty-utils"
gem "nilify_blanks"
gem "nio4r"
gem "puma"
gem "rails", "= 5.2.8.1"
gem "resolv", "~> 0.2.1"
gem "secure_headers"
gem "sentry-raven"
gem "turbolinks", "~> 5"
group :development, :assets do
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.2'
gem 'jquery-rails'
gem "coffee-rails", "~> 4.2"
gem "jquery-rails"
gem "sass-rails", "~> 5.0"
gem "uglifier", ">= 1.3.0"
end
group :development, :test do
gem 'byebug'
gem "byebug"
end
group :development do
gem 'annotate'
gem 'rspec', require: false
gem 'rspec-rails', require: false
gem "factory_bot_rails", "~> 4.0", require: false
gem "annotate"
gem "database_cleaner", require: false
gem "factory_bot_rails", "~> 4.0", require: false
gem "rspec", require: false
gem "rspec-rails", require: false
gem "rubocop"
gem "rubocop-rails"
end

عرض الملف

@@ -1,6 +1,6 @@
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
require_relative 'config/application'
require_relative "config/application"
Rails.application.load_tasks

عرض الملف

@@ -1,19 +1,19 @@
authenticator :server do
friendly_name "Server Authenticator"
header "X-Server-API-Key", "The API token for a server that you wish to authenticate with.", :example => 'f29a45f0d4e1744ebaee'
error 'InvalidServerAPIKey', "The API token provided in X-Server-API-Key was not valid.", :attributes => {:token => "The token that was looked up"}
error 'ServerSuspended', "The mail server has been suspended"
header "X-Server-API-Key", "The API token for a server that you wish to authenticate with.", example: "f29a45f0d4e1744ebaee"
error "InvalidServerAPIKey", "The API token provided in X-Server-API-Key was not valid.", attributes: { token: "The token that was looked up" }
error "ServerSuspended", "The mail server has been suspended"
lookup do
if key = request.headers['X-Server-API-Key']
if credential = Credential.where(:type => 'API', :key => key).first
if key = request.headers["X-Server-API-Key"]
if credential = Credential.where(type: "API", key: key).first
if credential.server.suspended?
error 'ServerSuspended'
error "ServerSuspended"
else
credential.use
credential
end
else
error 'InvalidServerAPIKey', :token => key
error "InvalidServerAPIKey", token: key
end
end
end

عرض الملف

@@ -6,35 +6,34 @@ controller :messages do
action :message do
title "Return message details"
description "Returns all details about a message"
param :id, "The ID of the message", :type => Integer, :required => true
returns Hash, :structure => :message, :structure_opts => {:paramable => {:expansions => false}}
error 'MessageNotFound', "No message found matching provided ID", :attributes => {:id => "The ID of the message"}
param :id, "The ID of the message", type: Integer, required: true
returns Hash, structure: :message, structure_opts: { paramable: { expansions: false } }
error "MessageNotFound", "No message found matching provided ID", attributes: { id: "The ID of the message" }
action do
begin
message = identity.server.message(params.id)
rescue Postal::MessageDB::Message::NotFound => e
error 'MessageNotFound', :id => params.id
error "MessageNotFound", id: params.id
end
structure :message, message, :return => true
structure :message, message, return: true
end
end
action :deliveries do
title "Return deliveries for a message"
description "Returns an array of deliveries which have been attempted for this message"
param :id, "The ID of the message", :type => Integer, :required => true
returns Array, :structure => :delivery, :structure_opts => {:full => true}
error 'MessageNotFound', "No message found matching provided ID", :attributes => {:id => "The ID of the message"}
param :id, "The ID of the message", type: Integer, required: true
returns Array, structure: :delivery, structure_opts: { full: true }
error "MessageNotFound", "No message found matching provided ID", attributes: { id: "The ID of the message" }
action do
begin
message = identity.server.message(params.id)
rescue Postal::MessageDB::Message::NotFound => e
error 'MessageNotFound', :id => params.id
error "MessageNotFound", id: params.id
end
message.deliveries.map do |d|
structure :delivery, d
end
end
end
end

عرض الملف

@@ -7,30 +7,30 @@ controller :send do
title "Send a message"
description "This action allows you to send a message by providing the appropriate options"
# Acceptable Parameters
param :to, "The e-mail addresses of the recipients (max 50)", :type => Array
param :cc, "The e-mail addresses of any CC contacts (max 50)", :type => Array
param :bcc, "The e-mail addresses of any BCC contacts (max 50)", :type => Array
param :from, "The e-mail address for the From header", :type => String
param :sender, "The e-mail address for the Sender header", :type => String
param :subject, "The subject of the e-mail", :type => String
param :tag, "The tag of the e-mail", :type => String
param :reply_to, "Set the reply-to address for the mail", :type => String
param :plain_body, "The plain text body of the e-mail", :type => String
param :html_body, "The HTML body of the e-mail", :type => String
param :attachments, "An array of attachments for this e-mail", :type => Array
param :headers, "A hash of additional headers", :type => Hash
param :bounce, "Is this message a bounce?", :type => :boolean
param :to, "The e-mail addresses of the recipients (max 50)", type: Array
param :cc, "The e-mail addresses of any CC contacts (max 50)", type: Array
param :bcc, "The e-mail addresses of any BCC contacts (max 50)", type: Array
param :from, "The e-mail address for the From header", type: String
param :sender, "The e-mail address for the Sender header", type: String
param :subject, "The subject of the e-mail", type: String
param :tag, "The tag of the e-mail", type: String
param :reply_to, "Set the reply-to address for the mail", type: String
param :plain_body, "The plain text body of the e-mail", type: String
param :html_body, "The HTML body of the e-mail", type: String
param :attachments, "An array of attachments for this e-mail", type: Array
param :headers, "A hash of additional headers", type: Hash
param :bounce, "Is this message a bounce?", type: :boolean
# Errors
error 'ValidationError', "The provided data was not sufficient to send an email", :attributes => {:errors => "A hash of error details"}
error 'NoRecipients', "There are no recipients defined to receive this message"
error 'NoContent', "There is no content defined for this e-mail"
error 'TooManyToAddresses', "The maximum number of To addresses has been reached (maximum 50)"
error 'TooManyCCAddresses', "The maximum number of CC addresses has been reached (maximum 50)"
error 'TooManyBCCAddresses', "The maximum number of BCC addresses has been reached (maximum 50)"
error 'FromAddressMissing', "The From address is missing and is required"
error 'UnauthenticatedFromAddress', "The From address is not authorised to send mail from this server"
error 'AttachmentMissingName', "An attachment is missing a name"
error 'AttachmentMissingData', "An attachment is missing data"
error "ValidationError", "The provided data was not sufficient to send an email", attributes: { errors: "A hash of error details" }
error "NoRecipients", "There are no recipients defined to receive this message"
error "NoContent", "There is no content defined for this e-mail"
error "TooManyToAddresses", "The maximum number of To addresses has been reached (maximum 50)"
error "TooManyCCAddresses", "The maximum number of CC addresses has been reached (maximum 50)"
error "TooManyBCCAddresses", "The maximum number of BCC addresses has been reached (maximum 50)"
error "FromAddressMissing", "The From address is missing and is required"
error "UnauthenticatedFromAddress", "The From address is not authorised to send mail from this server"
error "AttachmentMissingName", "An attachment is missing a name"
error "AttachmentMissingData", "An attachment is missing data"
# Return
returns Hash
# Action
@@ -51,13 +51,14 @@ controller :send do
attributes[:attachments] = []
(params.attachments || []).each do |attachment|
next unless attachment.is_a?(Hash)
attributes[:attachments] << {:name => attachment['name'], :content_type => attachment['content_type'], :data => attachment['data'], :base64 => true}
attributes[:attachments] << { name: attachment["name"], content_type: attachment["content_type"], data: attachment["data"], base64: true }
end
message = OutgoingMessagePrototype.new(identity.server, request.ip, 'api', attributes)
message = OutgoingMessagePrototype.new(identity.server, request.ip, "api", attributes)
message.credential = identity
if message.valid?
result = message.create_messages
{:message_id => message.message_id, :messages => result}
{ message_id: message.message_id, messages: result }
else
error message.errors.first
end
@@ -67,44 +68,43 @@ controller :send do
action :raw do
title "Send a raw RFC2882 message"
description "This action allows you to send us a raw RFC2822 formatted message along with the recipients that it should be sent to. This is similar to sending a message through our SMTP service."
param :mail_from, "The address that should be logged as sending the message", :type => String, :required => true
param :rcpt_to, "The addresses this message should be sent to", :type => Array, :required => true
param :data, "A base64 encoded RFC2822 message to send", :type => String, :required => true
param :bounce, "Is this message a bounce?", :type => :boolean
param :mail_from, "The address that should be logged as sending the message", type: String, required: true
param :rcpt_to, "The addresses this message should be sent to", type: Array, required: true
param :data, "A base64 encoded RFC2822 message to send", type: String, required: true
param :bounce, "Is this message a bounce?", type: :boolean
returns Hash
error 'UnauthenticatedFromAddress', "The From address is not authorised to send mail from this server"
error "UnauthenticatedFromAddress", "The From address is not authorised to send mail from this server"
action do
# Decode the raw message
raw_message = Base64.decode64(params.data)
# Parse through mail to get the from/sender headers
mail = Mail.new(raw_message.split("\r\n\r\n", 2).first)
from_headers = {'from' => mail.from, 'sender' => mail.sender}
from_headers = { "from" => mail.from, "sender" => mail.sender }
authenticated_domain = identity.server.find_authenticated_domain_from_headers(from_headers)
# If we're not authenticated, don't continue
if authenticated_domain.nil?
error 'UnauthenticatedFromAddress'
error "UnauthenticatedFromAddress"
end
# Store the result ready to return
result = {:message_id => nil, :messages => {}}
result = { message_id: nil, messages: {} }
params.rcpt_to.uniq.each do |rcpt_to|
message = identity.server.message_db.new_message
message.rcpt_to = rcpt_to
message.mail_from = params.mail_from
message.raw_message = raw_message
message.received_with_ssl = true
message.scope = 'outgoing'
message.scope = "outgoing"
message.domain_id = authenticated_domain.id
message.credential_id = identity.id
message.bounce = params.bounce ? 1 : 0
message.save
result[:message_id] = message.message_id if result[:message_id].nil?
result[:messages][rcpt_to] = {:id => message.id, :token => message.token}
result[:messages][rcpt_to] = { id: message.id, token: message.token }
end
result
end
end
end

عرض الملف

@@ -2,9 +2,9 @@ structure :delivery do
basic :id
basic :status
basic :details
basic :output, :value => proc { o.output&.strip }
basic :sent_with_ssl, :value => proc { o.sent_with_ssl == 1 }
basic :output, value: proc { o.output&.strip }
basic :sent_with_ssl, value: proc { o.sent_with_ssl == 1 }
basic :log_id
basic :time, :value => proc { o.time&.to_f }
basic :timestamp, :value => proc { o.timestamp.to_f }
basic :time, value: proc { o.time&.to_f }
basic :timestamp, value: proc { o.timestamp.to_f }
end

عرض الملف

@@ -2,65 +2,65 @@ structure :message do
basic :id
basic :token
expansion(:status) {
expansion(:status) do
{
:status => o.status,
:last_delivery_attempt => o.last_delivery_attempt ? o.last_delivery_attempt.to_f : nil,
:held => o.held == 1 ? true : false,
:hold_expiry => o.hold_expiry ? o.hold_expiry.to_f : nil
}
status: o.status,
last_delivery_attempt: o.last_delivery_attempt ? o.last_delivery_attempt.to_f : nil,
held: o.held == 1,
hold_expiry: o.hold_expiry ? o.hold_expiry.to_f : nil
}
end
expansion(:details) {
expansion(:details) do
{
:rcpt_to => o.rcpt_to,
:mail_from => o.mail_from,
:subject => o.subject,
:message_id => o.message_id,
:timestamp => o.timestamp.to_f,
:direction => o.scope,
:size => o.size,
:bounce => o.bounce,
:bounce_for_id => o.bounce_for_id,
:tag => o.tag,
:received_with_ssl => o.received_with_ssl
}
rcpt_to: o.rcpt_to,
mail_from: o.mail_from,
subject: o.subject,
message_id: o.message_id,
timestamp: o.timestamp.to_f,
direction: o.scope,
size: o.size,
bounce: o.bounce,
bounce_for_id: o.bounce_for_id,
tag: o.tag,
received_with_ssl: o.received_with_ssl
}
end
expansion(:inspection) {
expansion(:inspection) do
{
:inspected => o.inspected == 1 ? true : false,
:spam => o.spam == 1 ? true : false,
:spam_score => o.spam_score.to_f,
:threat => o.threat == 1 ? true : false,
:threat_details => o.threat_details
}
inspected: o.inspected == 1,
spam: o.spam == 1,
spam_score: o.spam_score.to_f,
threat: o.threat == 1,
threat_details: o.threat_details
}
end
expansion(:plain_body) { o.plain_body }
expansion(:html_body) { o.html_body }
expansion(:attachments) {
expansion(:attachments) do
o.attachments.map do |attachment|
{
:filename => attachment.filename.to_s,
:content_type => attachment.mime_type,
:data => Base64.encode64(attachment.body.to_s),
:size => attachment.body.to_s.bytesize,
:hash => Digest::SHA1.hexdigest(attachment.body.to_s)
filename: attachment.filename.to_s,
content_type: attachment.mime_type,
data: Base64.encode64(attachment.body.to_s),
size: attachment.body.to_s.bytesize,
hash: Digest::SHA1.hexdigest(attachment.body.to_s)
}
end
}
end
expansion(:headers) { o.headers }
expansion(:raw_message) { Base64.encode64(o.raw_message) }
expansion(:activity_entries) {
expansion(:activity_entries) do
{
:loads => o.loads,
:clicks => o.clicks
}
loads: o.loads,
clicks: o.clicks
}
end
end

عرض الملف

@@ -19,7 +19,7 @@ class AddressEndpointsController < ApplicationController
flash[:notice] = params[:return_notice] if params[:return_notice].present?
redirect_to_with_json [:return_to, [organization, @server, :address_endpoints]]
else
render_form_errors 'new', @address_endpoint
render_form_errors "new", @address_endpoint
end
end
@@ -27,7 +27,7 @@ class AddressEndpointsController < ApplicationController
if @address_endpoint.update(safe_params)
redirect_to_with_json [organization, @server, :address_endpoints]
else
render_form_errors 'edit', @address_endpoint
render_form_errors "edit", @address_endpoint
end
end

عرض الملف

@@ -1,4 +1,4 @@
require 'authie/session'
require "authie/session"
class ApplicationController < ActionController::Base
@@ -7,37 +7,37 @@ class ApplicationController < ActionController::Base
before_action :login_required
before_action :set_timezone
rescue_from Authie::Session::InactiveSession, :with => :auth_session_error
rescue_from Authie::Session::ExpiredSession, :with => :auth_session_error
rescue_from Authie::Session::BrowserMismatch, :with => :auth_session_error
rescue_from Authie::Session::InactiveSession, with: :auth_session_error
rescue_from Authie::Session::ExpiredSession, with: :auth_session_error
rescue_from Authie::Session::BrowserMismatch, with: :auth_session_error
private
def login_required
unless logged_in?
redirect_to login_path(:return_to => request.fullpath)
end
return if logged_in?
redirect_to login_path(return_to: request.fullpath)
end
def admin_required
if logged_in?
unless current_user.admin?
render :plain => "Not permitted"
render plain: "Not permitted"
end
else
redirect_to login_path(:return_to => request.fullpath)
redirect_to login_path(return_to: request.fullpath)
end
end
def require_organization_owner
unless organization.owner == current_user
redirect_to organization_root_path(organization), :alert => "This page can only be accessed by the organization's owner (#{organization.owner.name})"
end
return if organization.owner == current_user
redirect_to organization_root_path(organization), alert: "This page can only be accessed by the organization's owner (#{organization.owner.name})"
end
def auth_session_error(exception)
Rails.logger.info "AuthSessionError: #{exception.class}: #{exception.message}"
redirect_to login_path(:return_to => request.fullpath)
redirect_to login_path(return_to: request.fullpath)
end
def page_title
@@ -46,7 +46,7 @@ class ApplicationController < ActionController::Base
helper_method :page_title
def redirect_to_with_return_to(url, *args)
if params[:return_to].blank? || !params[:return_to].starts_with?('/')
if params[:return_to].blank? || !params[:return_to].starts_with?("/")
redirect_to url_with_return_to(url), *args
else
redirect_to url_with_return_to(url), *args
@@ -54,7 +54,7 @@ class ApplicationController < ActionController::Base
end
def set_timezone
Time.zone = logged_in? ? current_user.time_zone : 'UTC'
Time.zone = logged_in? ? current_user.time_zone : "UTC"
end
def append_info_to_payload(payload)
@@ -64,7 +64,7 @@ class ApplicationController < ActionController::Base
end
def url_with_return_to(url)
if params[:return_to].blank? || !params[:return_to].starts_with?('/')
if params[:return_to].blank? || !params[:return_to].starts_with?("/")
url_for(url)
else
params[:return_to]
@@ -83,14 +83,14 @@ class ApplicationController < ActionController::Base
end
respond_to do |wants|
wants.html { redirect_to url }
wants.json { render :json => {:redirect_to => url} }
wants.json { render json: { redirect_to: url } }
end
end
def render_form_errors(action_name, object)
respond_to do |wants|
wants.html { render action_name }
wants.json { render :json => {:form_errors => object.errors.full_messages}, :status => 422 }
wants.json { render json: { form_errors: object.errors.full_messages }, status: :unprocessable_entity }
end
end
@@ -102,7 +102,7 @@ class ApplicationController < ActionController::Base
render options[:render_action]
end
end
wants.json { render :json => {:flash => {type => message}} }
wants.json { render json: { flash: { type => message } } }
end
end
@@ -111,7 +111,7 @@ class ApplicationController < ActionController::Base
auth_session.invalidate!
reset_session
end
Authie::Session.start(self, :user => user)
Authie::Session.start(self, user: user)
@current_user = user
end

عرض الملف

@@ -18,7 +18,7 @@ class CredentialsController < ApplicationController
if @credential.save
redirect_to_with_json [organization, @server, :credentials]
else
render_form_errors 'new', @credential
render_form_errors "new", @credential
end
end
@@ -26,7 +26,7 @@ class CredentialsController < ApplicationController
if @credential.update(params.require(:credential).permit(:name, :key, :hold))
redirect_to_with_json [organization, @server, :credentials]
else
render_form_errors 'edit', @credential
render_form_errors "edit", @credential
end
end

عرض الملف

@@ -28,7 +28,7 @@ class DomainsController < ApplicationController
@domain = scope.build(params.require(:domain).permit(:name, :verification_method))
if current_user.admin?
@domain.verification_method = 'DNS'
@domain.verification_method = "DNS"
@domain.verified_at = Time.now
end
@@ -39,7 +39,7 @@ class DomainsController < ApplicationController
redirect_to_with_json [:verify, organization, @server, @domain]
end
else
render_form_errors 'new', @domain
render_form_errors "new", @domain
end
end
@@ -50,56 +50,57 @@ class DomainsController < ApplicationController
def verify
if @domain.verified?
redirect_to [organization, @server, :domains], :alert => "#{@domain.name} has already been verified."
redirect_to [organization, @server, :domains], alert: "#{@domain.name} has already been verified."
return
end
if request.post?
return unless request.post?
case @domain.verification_method
when 'DNS'
when "DNS"
if @domain.verify_with_dns
redirect_to_with_json [:setup, organization, @server, @domain], :notice => "#{@domain.name} has been verified successfully. You now need to configure your DNS records."
redirect_to_with_json [:setup, organization, @server, @domain], notice: "#{@domain.name} has been verified successfully. You now need to configure your DNS records."
else
respond_to do |wants|
wants.html { flash.now[:alert] = "We couldn't verify your domain. Please double check you've added the TXT record correctly." }
wants.json { render :json => {:flash => {:alert => "We couldn't verify your domain. Please double check you've added the TXT record correctly."}}}
wants.json { render json: { flash: { alert: "We couldn't verify your domain. Please double check you've added the TXT record correctly." } } }
end
end
when 'Email'
when "Email"
if params[:code]
if @domain.verification_token == params[:code].to_s.strip
@domain.verify
redirect_to_with_json [:setup, organization, @server, @domain], :notice => "#{@domain.name} has been verified successfully. You now need to configure your DNS records."
redirect_to_with_json [:setup, organization, @server, @domain], notice: "#{@domain.name} has been verified successfully. You now need to configure your DNS records."
else
respond_to do |wants|
wants.html { flash.now[:alert] = "Invalid verification code. Please check and try again." }
wants.json { render :json => {:flash => {:alert => "Invalid verification code. Please check and try again."}}}
wants.json { render json: { flash: { alert: "Invalid verification code. Please check and try again." } } }
end
end
elsif params[:email_address].present?
raise Postal::Error, "Invalid email address" unless @domain.verification_email_addresses.include?(params[:email_address])
AppMailer.verify_domain(@domain, params[:email_address], current_user).deliver
if @domain.owner.is_a?(Server)
redirect_to_with_json verify_organization_server_domain_path(organization, @server, @domain, :email_address => params[:email_address])
redirect_to_with_json verify_organization_server_domain_path(organization, @server, @domain, email_address: params[:email_address])
else
redirect_to_with_json verify_organization_domain_path(organization, @domain, :email_address => params[:email_address])
end
redirect_to_with_json verify_organization_domain_path(organization, @domain, email_address: params[:email_address])
end
end
end
end
def setup
unless @domain.verified?
redirect_to [:verify, organization, @server, @domain], :alert => "You can't set up DNS for this domain until it has been verified."
end
return if @domain.verified?
redirect_to [:verify, organization, @server, @domain], alert: "You can't set up DNS for this domain until it has been verified."
end
def check
if @domain.check_dns(:manual)
redirect_to_with_json [organization, @server, :domains], :notice => "Your DNS records for #{@domain.name} look good!"
redirect_to_with_json [organization, @server, :domains], notice: "Your DNS records for #{@domain.name} look good!"
else
redirect_to_with_json [:setup, organization, @server, @domain], :alert => "There seems to be something wrong with your DNS records. Check below for information."
redirect_to_with_json [:setup, organization, @server, @domain], alert: "There seems to be something wrong with your DNS records. Check below for information."
end
end

عرض الملف

@@ -19,7 +19,7 @@ class HTTPEndpointsController < ApplicationController
flash[:notice] = params[:return_notice] if params[:return_notice].present?
redirect_to_with_json [:return_to, [organization, @server, :http_endpoints]]
else
render_form_errors 'new', @http_endpoint
render_form_errors "new", @http_endpoint
end
end
@@ -27,7 +27,7 @@ class HTTPEndpointsController < ApplicationController
if @http_endpoint.update(safe_params)
redirect_to_with_json [organization, @server, :http_endpoints]
else
render_form_errors 'edit', @http_endpoint
render_form_errors "edit", @http_endpoint
end
end

عرض الملف

@@ -13,7 +13,7 @@ class IPAddressesController < ApplicationController
if @ip_address.save
redirect_to_with_json [:edit, @ip_pool]
else
render_form_errors 'new', @ip_address
render_form_errors "new", @ip_address
end
end
@@ -21,7 +21,7 @@ class IPAddressesController < ApplicationController
if @ip_address.update(safe_params)
redirect_to_with_json [:edit, @ip_pool]
else
render_form_errors 'edit', @ip_address
render_form_errors "edit", @ip_address
end
end

عرض الملف

@@ -29,7 +29,7 @@ class IPPoolRulesController < ApplicationController
if @ip_pool_rule.save
redirect_to_with_json [organization, @server, :ip_pool_rules]
else
render_form_errors 'new', @ip_pool_rule
render_form_errors "new", @ip_pool_rule
end
end
@@ -37,7 +37,7 @@ class IPPoolRulesController < ApplicationController
if @ip_pool_rule.update(safe_params)
redirect_to_with_json [organization, @server, :ip_pool_rules]
else
render_form_errors 'edit', @ip_pool_rule
render_form_errors "edit", @ip_pool_rule
end
end

عرض الملف

@@ -14,25 +14,25 @@ class IPPoolsController < ApplicationController
def create
@ip_pool = IPPool.new(safe_params)
if @ip_pool.save
redirect_to_with_json [:edit, @ip_pool], :notice => "IP Pool has been added successfully. You can now add IP addresses to it."
redirect_to_with_json [:edit, @ip_pool], notice: "IP Pool has been added successfully. You can now add IP addresses to it."
else
render_form_errors 'new', @ip_pool
render_form_errors "new", @ip_pool
end
end
def update
if @ip_pool.update(safe_params)
redirect_to_with_json [:edit, @ip_pool], :notice => "IP Pool has been updated."
redirect_to_with_json [:edit, @ip_pool], notice: "IP Pool has been updated."
else
render_form_errors 'edit', @ip_pool
render_form_errors "edit", @ip_pool
end
end
def destroy
@ip_pool.destroy
redirect_to_with_json :ip_pools, :notice => "IP pool has been removed successfully."
redirect_to_with_json :ip_pools, notice: "IP pool has been removed successfully."
rescue ActiveRecord::DeleteRestrictionError => e
redirect_to_with_json [:edit, @ip_pool], :alert => "IP pool cannot be removed because it still has associated addresses or servers."
redirect_to_with_json [:edit, @ip_pool], alert: "IP pool cannot be removed because it still has associated addresses or servers."
end
private

عرض الملف

@@ -1,4 +1,4 @@
class MessagesController < ApplicationController
class MessagesController < ApplicationController
include WithinOrganization
@@ -6,12 +6,12 @@
before_action { params[:id] && @message = @server.message_db.message(params[:id].to_i) }
def new
if params[:direction] == 'incoming'
@message = IncomingMessagePrototype.new(@server, request.ip, 'web-ui', {})
if params[:direction] == "incoming"
@message = IncomingMessagePrototype.new(@server, request.ip, "web-ui", {})
@message.from = session[:test_in_from] || current_user.email_tag
@message.to = @server.routes.order(:name).first&.description
else
@message = OutgoingMessagePrototype.new(@server, request.ip, 'web-ui', {})
@message = OutgoingMessagePrototype.new(@server, request.ip, "web-ui", {})
@message.to = session[:test_out_to] || current_user.email_address
if domain = @server.domains.verified.order(:name).first
@message.from = "test@#{domain.name}"
@@ -22,28 +22,28 @@
end
def create
if params[:direction] == 'incoming'
if params[:direction] == "incoming"
session[:test_in_from] = params[:message][:from] if params[:message]
@message = IncomingMessagePrototype.new(@server, request.ip, 'web-ui', params[:message])
@message.attachments = [{:name => "test.txt", :content_type => "text/plain", :data => "Hello world!"}]
@message = IncomingMessagePrototype.new(@server, request.ip, "web-ui", params[:message])
@message.attachments = [{ name: "test.txt", content_type: "text/plain", data: "Hello world!" }]
else
session[:test_out_to] = params[:message][:to] if params[:message]
@message = OutgoingMessagePrototype.new(@server, request.ip, 'web-ui', params[:message])
@message = OutgoingMessagePrototype.new(@server, request.ip, "web-ui", params[:message])
end
if result = @message.create_messages
if result.size == 1
redirect_to_with_json organization_server_message_path(organization, @server, result.first.last[:id]), :notice => "Message was queued successfully"
redirect_to_with_json organization_server_message_path(organization, @server, result.first.last[:id]), notice: "Message was queued successfully"
else
redirect_to_with_json [:queue, organization, @server], :notice => "Messages queued successfully "
redirect_to_with_json [:queue, organization, @server], notice: "Messages queued successfully "
end
else
respond_to do |wants|
wants.html do
flash.now[:alert] = "Your message could not be sent. Ensure that all fields are completed fully. #{result.errors.inspect}"
render 'new'
render "new"
end
wants.json do
render :json => {:flash => {:alert => "Your message could not be sent. Please check all field are completed fully."}}
render json: { flash: { alert: "Your message could not be sent. Please check all field are completed fully." } }
end
end
@@ -52,58 +52,62 @@
def outgoing
@searchable = true
get_messages('outgoing')
get_messages("outgoing")
respond_to do |wants|
wants.html
wants.json { render :json => {
:flash => flash.each_with_object({}) { |(type, message), hash| hash[type] = message},
:region_html => render_to_string(:partial => 'index', :formats => [:html])
}}
wants.json do
render json: {
flash: flash.each_with_object({}) { |(type, message), hash| hash[type] = message },
region_html: render_to_string(partial: "index", formats: [:html])
}
end
end
end
def incoming
@searchable = true
get_messages('incoming')
get_messages("incoming")
respond_to do |wants|
wants.html
wants.json { render :json => {
:flash => flash.each_with_object({}) { |(type, message), hash| hash[type] = message},
:region_html => render_to_string(:partial => 'index', :formats => [:html])
}}
wants.json do
render json: {
flash: flash.each_with_object({}) { |(type, message), hash| hash[type] = message },
region_html: render_to_string(partial: "index", formats: [:html])
}
end
end
end
def held
get_messages('held')
get_messages("held")
end
def deliveries
render :json => {:html => render_to_string(:partial => 'deliveries', :locals => {:message => @message})}
render json: { html: render_to_string(partial: "deliveries", locals: { message: @message }) }
end
def html_raw
render :html => @message.html_body_without_tracking_image.html_safe
render html: @message.html_body_without_tracking_image.html_safe
end
def spam_checks
@spam_checks = @message.spam_checks.sort_by { |s| s['score']}.reverse
@spam_checks = @message.spam_checks.sort_by { |s| s["score"] }.reverse
end
def attachment
if @message.attachments.size > params[:attachment].to_i
attachment = @message.attachments[params[:attachment].to_i]
send_data attachment.body, :content_type => attachment.mime_type, :disposition => 'download', :filename => attachment.filename
send_data attachment.body, content_type: attachment.mime_type, disposition: "download", filename: attachment.filename
else
redirect_to attachments_organization_server_message_path(organization, @server, @message.id), :alert => "Attachment not found. Choose an attachment from the list below."
redirect_to attachments_organization_server_message_path(organization, @server, @message.id), alert: "Attachment not found. Choose an attachment from the list below."
end
end
def download
if @message.raw_message
send_data @message.raw_message, :filename => "Message-#{organization.permalink}-#{@server.permalink}-#{@message.id}.eml", :content_type => "text/plain"
send_data @message.raw_message, filename: "Message-#{organization.permalink}-#{@server.permalink}-#{@message.id}.eml", content_type: "text/plain"
else
redirect_to organization_server_message_path(organization, @server, @message.id), :alert => "We no longer have the raw message stored for this message."
redirect_to organization_server_message_path(organization, @server, @message.id), alert: "We no longer have the raw message stored for this message."
end
end
@@ -113,10 +117,10 @@
@message.queued_message.queue!
flash[:notice] = "This message will be retried shortly."
elsif @message.held?
@message.add_to_message_queue(:manual => true)
@message.add_to_message_queue(manual: true)
flash[:notice] = "This message has been released. Delivery will be attempted shortly."
else
@message.add_to_message_queue(:manual => true)
@message.add_to_message_queue(manual: true)
flash[:notice] = "This message will be redelivered shortly."
end
else
@@ -148,10 +152,10 @@
private
def get_messages(scope)
if scope == 'held'
options = {:where => {:held => 1}}
if scope == "held"
options = { where: { held: 1 } }
else
options = {:where => {:scope => scope, :spam => false}, :order => :timestamp, :direction => 'desc'}
options = { where: { scope: scope, spam: false }, order: :timestamp, direction: "desc" }
if @query = (params[:query] || session["msg_query_#{@server.id}_#{scope}"]).presence
session["msg_query_#{@server.id}_#{scope}"] = @query
@@ -160,8 +164,8 @@
flash.now[:alert] = "It doesn't appear you entered anything to filter on. Please double check your query."
else
@queried = true
if qs[:order] == 'oldest-first'
options[:direction] = 'asc'
if qs[:order] == "oldest-first"
options[:direction] = "asc"
end
options[:where][:rcpt_to] = qs[:to] if qs[:to]
@@ -176,7 +180,7 @@
end
options[:where][:tag] = qs[:tag] if qs[:tag]
options[:where][:id] = qs[:id] if qs[:id]
options[:where][:spam] = true if qs[:spam] == 'yes' || qs[:spam] == 'y'
options[:where][:spam] = true if qs[:spam] == "yes" || qs[:spam] == "y"
if qs[:before] || qs[:after]
options[:where][:timestamp] = {}
if qs[:before]
@@ -208,21 +212,19 @@
def get_time_from_string(string)
begin
if string =~ /\A(\d{2,4})\-(\d{2})\-(\d{2}) (\d{2})\:(\d{2})\z/
time = Time.new($1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i)
elsif string =~ /\A(\d{2,4})\-(\d{2})\-(\d{2})\z/
time = Time.new($1.to_i, $2.to_i, $3.to_i, 0)
if string =~ /\A(\d{2,4})-(\d{2})-(\d{2}) (\d{2}):(\d{2})\z/
time = Time.new(::Regexp.last_match(1).to_i, ::Regexp.last_match(2).to_i, ::Regexp.last_match(3).to_i, ::Regexp.last_match(4).to_i, ::Regexp.last_match(5).to_i)
elsif string =~ /\A(\d{2,4})-(\d{2})-(\d{2})\z/
time = Time.new(::Regexp.last_match(1).to_i, ::Regexp.last_match(2).to_i, ::Regexp.last_match(3).to_i, 0)
else
time = Chronic.parse(string, :context => :past)
time = Chronic.parse(string, context: :past)
end
rescue
rescue StandardError
end
if time.nil?
raise TimeUndetermined, "Couldn't determine a suitable time from '#{string}'"
else
raise TimeUndetermined, "Couldn't determine a suitable time from '#{string}'" if time.nil?
time
end
end
end

عرض الملف

@@ -1,7 +1,7 @@
class OrganizationIPPoolsController < ApplicationController
include WithinOrganization
before_action :admin_required, :only => [:assignments]
before_action :admin_required, only: [:assignments]
def index
@ip_pools = organization.ip_pools.order(:name)
@@ -10,7 +10,7 @@ class OrganizationIPPoolsController < ApplicationController
def assignments
organization.ip_pool_ids = params[:ip_pools]
organization.save!
redirect_to [organization, :ip_pools], :notice => "Organization IP pools have been updated successfully"
redirect_to [organization, :ip_pools], notice: "Organization IP pools have been updated successfully"
end
end

عرض الملف

@@ -1,6 +1,6 @@
class OrganizationsController < ApplicationController
before_action :admin_required, :only => [:new, :create, :delete, :destroy]
before_action :admin_required, only: [:new, :create, :delete, :destroy]
def index
if current_user.admin?
@@ -17,49 +17,49 @@ class OrganizationsController < ApplicationController
@organization = Organization.new
end
def edit
@organization_obj = current_user.organizations_scope.find(organization.id)
end
def create
@organization = Organization.new(params.require(:organization).permit(:name, :permalink))
@organization.owner = current_user
if @organization.save
redirect_to_with_json organization_root_path(@organization)
else
render_form_errors 'new', @organization
render_form_errors "new", @organization
end
end
def edit
@organization_obj = current_user.organizations_scope.find(organization.id)
end
def update
@organization_obj = current_user.organizations_scope.find(organization.id)
if @organization_obj.update(params.require(:organization).permit(:name, :time_zone))
redirect_to_with_json organization_settings_path(@organization_obj), :notice => "Settings for #{@organization_obj.name} have been saved successfully."
redirect_to_with_json organization_settings_path(@organization_obj), notice: "Settings for #{@organization_obj.name} have been saved successfully."
else
render_form_errors 'edit', @organization_obj
render_form_errors "edit", @organization_obj
end
end
def destroy
unless current_user.authenticate(params[:password])
respond_to do |wants|
wants.html { redirect_to organization_delete_path(@organization), :alert => "The password you entered was not valid. Please check and try again." }
wants.json { render :json => {:alert => "The password you entered was invalid. Please check and try again."} }
wants.html { redirect_to organization_delete_path(@organization), alert: "The password you entered was not valid. Please check and try again." }
wants.json { render json: { alert: "The password you entered was invalid. Please check and try again." } }
end
return
end
organization.soft_destroy
redirect_to_with_json root_path(:nrd => 1), :notice => "#{@organization.name} has been removed successfully."
redirect_to_with_json root_path(nrd: 1), notice: "#{@organization.name} has been removed successfully."
end
private
def organization
if [:edit, :update, :delete, :destroy].include?(action_name.to_sym)
return unless [:edit, :update, :delete, :destroy].include?(action_name.to_sym)
@organization ||= params[:org_permalink] ? current_user.organizations_scope.find_by_permalink!(params[:org_permalink]) : nil
end
end
helper_method :organization
end

عرض الملف

@@ -18,7 +18,7 @@ class RoutesController < ApplicationController
if @route.save
redirect_to_with_json [organization, @server, :routes]
else
render_form_errors 'new', @route
render_form_errors "new", @route
end
end
@@ -26,7 +26,7 @@ class RoutesController < ApplicationController
if @route.update(safe_params)
redirect_to_with_json [organization, @server, :routes]
else
render_form_errors 'edit', @route
render_form_errors "edit", @route
end
end
@@ -38,7 +38,7 @@ class RoutesController < ApplicationController
private
def safe_params
params.require(:route).permit(:name, :domain_id, :spam_mode, :_endpoint, :additional_route_endpoints_array => [])
params.require(:route).permit(:name, :domain_id, :spam_mode, :_endpoint, additional_route_endpoints_array: [])
end
end

عرض الملف

@@ -2,7 +2,7 @@ class ServersController < ApplicationController
include WithinOrganization
before_action :admin_required, :only => [:advanced, :suspend, :unsuspend]
before_action :admin_required, only: [:advanced, :suspend, :unsuspend]
before_action { params[:id] && @server = organization.servers.present.find_by_permalink!(params[:id]) }
def index
@@ -23,7 +23,7 @@ class ServersController < ApplicationController
@first_date = graph_data.first.first
@last_date = graph_data.last.first
@graph_data = graph_data.map(&:last)
@messages = @server.message_db.messages(:order => 'id', :direction => 'desc', :limit => 6)
@messages = @server.message_db.messages(order: "id", direction: "desc", limit: 6)
end
def new
@@ -35,7 +35,7 @@ class ServersController < ApplicationController
if @server.save
redirect_to_with_json organization_server_path(organization, @server)
else
render_form_errors 'new', @server
render_form_errors "new", @server
end
end
@@ -43,9 +43,9 @@ class ServersController < ApplicationController
extra_params = [:spam_threshold, :spam_failure_threshold, :postmaster_address]
extra_params += [:send_limit, :allow_sender, :log_smtp_data, :outbound_spam_threshold, :message_retention_days, :raw_message_retention_days, :raw_message_retention_size] if current_user.admin?
if @server.update(safe_params(*extra_params))
redirect_to_with_json organization_server_path(organization, @server), :notice => "Server settings have been updated"
redirect_to_with_json organization_server_path(organization, @server), notice: "Server settings have been updated"
else
render_form_errors 'edit', @server
render_form_errors "edit", @server
end
end
@@ -53,31 +53,31 @@ class ServersController < ApplicationController
unless current_user.authenticate(params[:password])
respond_to do |wants|
wants.html do
redirect_to [:delete, organization, @server], :alert => "The password you entered was not valid. Please check and try again."
redirect_to [:delete, organization, @server], alert: "The password you entered was not valid. Please check and try again."
end
wants.json do
render :json => {:alert => "The password you entere was invalid. Please check and try again"}
render json: { alert: "The password you entere was invalid. Please check and try again" }
end
end
return
end
@server.soft_destroy
redirect_to_with_json organization_root_path(organization), :notice => "#{@server.name} has been deleted successfully"
redirect_to_with_json organization_root_path(organization), notice: "#{@server.name} has been deleted successfully"
end
def queue
@messages = @server.queued_messages.order(:id => :desc).page(params[:page])
@messages = @server.queued_messages.order(id: :desc).page(params[:page])
@messages_with_message = @messages.include_message
end
def suspend
@server.suspend(params[:reason])
redirect_to_with_json [organization, @server], :notice => "Server has been suspended"
redirect_to_with_json [organization, @server], notice: "Server has been suspended"
end
def unsuspend
@server.unsuspend
redirect_to_with_json [organization, @server], :notice => "Server has been unsuspended"
redirect_to_with_json [organization, @server], notice: "Server has been unsuspended"
end
private

عرض الملف

@@ -1,8 +1,8 @@
class SessionsController < ApplicationController
layout 'sub'
layout "sub"
skip_before_action :login_required, :only => [:new, :create, :create_with_token, :begin_password_reset, :finish_password_reset, :ip, :raise_error]
skip_before_action :login_required, only: [:new, :create, :create_with_token, :begin_password_reset, :finish_password_reset, :ip, :raise_error]
def create
login(User.authenticate(params[:email_address], params[:password]))
@@ -10,13 +10,13 @@ class SessionsController < ApplicationController
redirect_to_with_return_to root_path
rescue Postal::Errors::AuthenticationError => e
flash.now[:alert] = "The credentials you've provided are incorrect. Please check and try again."
render 'new'
render "new"
end
def create_with_token
result = JWT.decode(params[:token], Postal.signing_key.to_s, 'HS256')[0]
if result['timestamp'] > 1.minute.ago.to_f
login(User.find(result['user'].to_i))
result = JWT.decode(params[:token], Postal.signing_key.to_s, "HS256")[0]
if result["timestamp"] > 1.minute.ago.to_f
login(User.find(result["user"].to_i))
redirect_to root_path
else
destroy
@@ -33,42 +33,42 @@ class SessionsController < ApplicationController
def persist
auth_session.persist! if logged_in?
render :plain => "OK"
render plain: "OK"
end
def begin_password_reset
if request.post?
if user = User.where(:email_address => params[:email_address]).first
return unless request.post?
if user = User.where(email_address: params[:email_address]).first
user.begin_password_reset(params[:return_to])
redirect_to login_path(:return_to => params[:return_to]), :notice => "Please check your e-mail and click the link in the e-mail we've sent you."
redirect_to login_path(return_to: params[:return_to]), notice: "Please check your e-mail and click the link in the e-mail we've sent you."
else
redirect_to login_reset_path(:return_to => params[:return_to]), :alert => "No user exists with that e-mail address. Please check and try again."
end
redirect_to login_reset_path(return_to: params[:return_to]), alert: "No user exists with that e-mail address. Please check and try again."
end
end
def finish_password_reset
@user = User.where(:password_reset_token => params[:token]).where("password_reset_token_valid_until > ?", Time.now).first
@user = User.where(password_reset_token: params[:token]).where("password_reset_token_valid_until > ?", Time.now).first
if @user.nil?
redirect_to login_path(:return_to => params[:return_to]), :alert => "This link has expired or never existed. Please choose reset password to try again."
redirect_to login_path(return_to: params[:return_to]), alert: "This link has expired or never existed. Please choose reset password to try again."
end
if request.post?
return unless request.post?
if params[:password].blank?
flash.now[:alert] = "You must enter a new password"
return
end
@user.password = params[:password]
@user.password_confirmation = params[:password_confirmation]
if @user.save
return unless @user.save
login(@user)
redirect_to_with_return_to root_path, :notice => "Your new password has been set and you've been logged in."
end
end
redirect_to_with_return_to root_path, notice: "Your new password has been set and you've been logged in."
end
def ip
render :plain => "ip: #{request.ip} remote ip: #{request.remote_ip}"
render plain: "ip: #{request.ip} remote ip: #{request.remote_ip}"
end
end

عرض الملف

@@ -1,4 +1,5 @@
class SMTPEndpointsController < ApplicationController
include WithinOrganization
before_action { @server = organization.servers.present.find_by_permalink!(params[:server_id]) }
before_action { params[:id] && @smtp_endpoint = @server.smtp_endpoints.find_by_uuid!(params[:id]) }
@@ -17,7 +18,7 @@ class SMTPEndpointsController < ApplicationController
flash[:notice] = params[:return_notice] if params[:return_notice].present?
redirect_to_with_json [:return_to, [organization, @server, :smtp_endpoints]]
else
render_form_errors 'new', @smtp_endpoint
render_form_errors "new", @smtp_endpoint
end
end
@@ -25,7 +26,7 @@ class SMTPEndpointsController < ApplicationController
if @smtp_endpoint.update(safe_params)
redirect_to_with_json [organization, @server, :smtp_endpoints]
else
render_form_errors 'edit', @smtp_endpoint
render_form_errors "edit", @smtp_endpoint
end
end

عرض الملف

@@ -1,4 +1,5 @@
class TrackDomainsController < ApplicationController
include WithinOrganization
before_action { @server = organization.servers.present.find_by_permalink!(params[:server_id]) }
before_action { params[:id] && @track_domain = @server.track_domains.find_by_uuid!(params[:id]) }
@@ -16,7 +17,7 @@ class TrackDomainsController < ApplicationController
if @track_domain.save
redirect_to_with_json [:return_to, [organization, @server, :track_domains]]
else
render_form_errors 'new', @track_domain
render_form_errors "new", @track_domain
end
end
@@ -24,7 +25,7 @@ class TrackDomainsController < ApplicationController
if @track_domain.update(params.require(:track_domain).permit(:track_loads, :track_clicks, :excluded_click_domains, :ssl_enabled))
redirect_to_with_json [organization, @server, :track_domains]
else
render_form_errors 'edit', @track_domain
render_form_errors "edit", @track_domain
end
end
@@ -35,15 +36,15 @@ class TrackDomainsController < ApplicationController
def check
if @track_domain.check_dns
redirect_to_with_json [organization, @server, :track_domains], :notice => "Your CNAME for #{@track_domain.full_name} looks good!"
redirect_to_with_json [organization, @server, :track_domains], notice: "Your CNAME for #{@track_domain.full_name} looks good!"
else
redirect_to_with_json [organization, @server, :track_domains], :alert => "There seems to be something wrong with your DNS record. Check documentation for information."
redirect_to_with_json [organization, @server, :track_domains], alert: "There seems to be something wrong with your DNS record. Check documentation for information."
end
end
def toggle_ssl
@track_domain.update(:ssl_enabled => !@track_domain.ssl_enabled)
redirect_to_with_json [organization, @server, :track_domains], :notice => "SSL settings for #{@track_domain.full_name} updated successfully."
@track_domain.update(ssl_enabled: !@track_domain.ssl_enabled)
redirect_to_with_json [organization, @server, :track_domains], notice: "SSL settings for #{@track_domain.full_name} updated successfully."
end
end

عرض الملف

@@ -1,16 +1,20 @@
class UserController < ApplicationController
skip_before_action :login_required, :only => [:new, :create, :join]
skip_before_action :login_required, only: [:new, :create, :join]
def new
@user_invite = UserInvite.active.find_by!(:uuid => params[:invite_token])
@user_invite = UserInvite.active.find_by!(uuid: params[:invite_token])
@user = User.new
@user.email_address = @user_invite.email_address
render :layout => 'sub'
render layout: "sub"
end
def edit
@user = User.find(current_user.id)
end
def create
@user_invite = UserInvite.active.find_by!(:uuid => params[:invite_token])
@user_invite = UserInvite.active.find_by!(uuid: params[:invite_token])
@user = User.new(params.require(:user).permit(:first_name, :last_name, :email_address, :password, :password_confirmation))
@user.email_verified_at = Time.now
if @user.save
@@ -18,19 +22,19 @@ class UserController < ApplicationController
self.current_user = @user
redirect_to root_path
else
render 'new', :layout => 'sub'
render "new", layout: "sub"
end
end
def join
if @invite = UserInvite.where(:uuid => params[:token]).where("expires_at > ?", Time.now).first
if @invite = UserInvite.where(uuid: params[:token]).where("expires_at > ?", Time.now).first
if logged_in?
if request.post?
@invite.accept(current_user)
redirect_to_with_json root_path(:nrd => 1), :notice => "Invitation has been accepted successfully. You now have access to this organization."
redirect_to_with_json root_path(nrd: 1), notice: "Invitation has been accepted successfully. You now have access to this organization."
elsif request.delete?
@invite.reject
redirect_to_with_json root_path(:nrd => 1), :notice => "Invitation has been rejected successfully."
redirect_to_with_json root_path(nrd: 1), notice: "Invitation has been rejected successfully."
else
@organizations = @invite.organizations.order(:name).to_a
end
@@ -38,14 +42,10 @@ class UserController < ApplicationController
redirect_to new_signup_path(params[:token])
end
else
redirect_to_with_json root_path(:nrd => 1), :alert => "The invite URL you have has expired. Please ask the person who invited you to re-send your invitation."
redirect_to_with_json root_path(nrd: 1), alert: "The invite URL you have has expired. Please ask the person who invited you to re-send your invitation."
end
end
def edit
@user = User.find(current_user.id)
end
def update
@user = User.find(current_user.id)
@user.attributes = params.require(:user).permit(:first_name, :last_name, :time_zone, :email_address, :password, :password_confirmation)
@@ -56,10 +56,10 @@ class UserController < ApplicationController
respond_to do |wants|
wants.html do
flash.now[:alert] = "The current password you have entered is incorrect. Please check and try again."
render 'edit'
render "edit"
end
wants.json do
render :json => {:alert => "The current password you've entered is incorrect. Please check and try again"}
render json: { alert: "The current password you've entered is incorrect. Please check and try again" }
end
end
return
@@ -69,24 +69,24 @@ class UserController < ApplicationController
if @user.save
if email_changed
redirect_to_with_json verify_path(:return_to => settings_path), :notice => "Your settings have been updated successfully. As you've changed, your e-mail address you'll need to verify it before you can continue."
redirect_to_with_json verify_path(return_to: settings_path), notice: "Your settings have been updated successfully. As you've changed, your e-mail address you'll need to verify it before you can continue."
else
redirect_to_with_json settings_path, :notice => "Your settings have been updated successfully."
redirect_to_with_json settings_path, notice: "Your settings have been updated successfully."
end
else
render_form_errors 'edit', @user
render_form_errors "edit", @user
end
end
def verify
if request.post?
return unless request.post?
if params[:code].to_s.strip == current_user.email_verification_token.to_s || (Rails.env.development? && params[:code].to_s.strip == "123456")
current_user.verify!
redirect_to_with_json [:return_to, root_path], :notice => "Thanks - your e-mail address has been verified successfully."
redirect_to_with_json [:return_to, root_path], notice: "Thanks - your e-mail address has been verified successfully."
else
flash_now :alert, "The code you've entered isn't correct. Please check and try again."
end
end
end
end

عرض الملف

@@ -11,45 +11,44 @@ class UsersController < ApplicationController
@user = User.new(admin: true)
end
def edit
end
def create
@user = User.new(params.require(:user).permit(:email_address, :first_name, :last_name, :password, :password_confirmation, :admin, organization_ids: []))
if @user.save
redirect_to_with_json :users, :notice => "#{@user.name} has been created successfully."
redirect_to_with_json :users, notice: "#{@user.name} has been created successfully."
else
render_form_errors 'new', @user
render_form_errors "new", @user
end
end
def edit
end
def update
@user.attributes = params.require(:user).permit(:email_address, :first_name, :last_name, :admin, organization_ids: [])
if @user == current_user && !@user.admin?
respond_to do |wants|
wants.html { redirect_to users_path, alert: "You cannot change your own admin status" }
wants.json { render :json => {:form_errors => ["You cannot change your own admin status"]}, :status => 422 }
wants.json { render json: { form_errors: ["You cannot change your own admin status"] }, status: :unprocessable_entity }
end
return
end
if @user.save
redirect_to_with_json :users, :notice => "Permissions for #{@user.name} have been updated successfully."
redirect_to_with_json :users, notice: "Permissions for #{@user.name} have been updated successfully."
else
render_form_errors 'edit', @user
render_form_errors "edit", @user
end
end
def destroy
if @user == current_user
redirect_to_with_json :users, :alert => "You cannot delete your own user."
redirect_to_with_json :users, alert: "You cannot delete your own user."
return
end
@user.destroy!
redirect_to_with_json :users, :notice => "#{@user.name} has been removed"
redirect_to_with_json :users, notice: "#{@user.name} has been removed"
end
end

عرض الملف

@@ -1,4 +1,5 @@
class WebhooksController < ApplicationController
include WithinOrganization
before_action { @server = organization.servers.present.find_by_permalink!(params[:server_id]) }
before_action { params[:id] && @webhook = @server.webhooks.find_by_uuid!(params[:id]) }
@@ -8,7 +9,7 @@ class WebhooksController < ApplicationController
end
def new
@webhook = @server.webhooks.build(:all_events => true)
@webhook = @server.webhooks.build(all_events: true)
end
def create
@@ -16,7 +17,7 @@ class WebhooksController < ApplicationController
if @webhook.save
redirect_to_with_json [organization, @server, :webhooks]
else
render_form_errors 'new', @webhook
render_form_errors "new", @webhook
end
end
@@ -24,7 +25,7 @@ class WebhooksController < ApplicationController
if @webhook.update(safe_params)
redirect_to_with_json [organization, @server, :webhooks]
else
render_form_errors 'edit', @webhook
render_form_errors "edit", @webhook
end
end
@@ -45,7 +46,7 @@ class WebhooksController < ApplicationController
private
def safe_params
params.require(:webhook).permit(:name, :url, :all_events, :enabled, :events => [])
params.require(:webhook).permit(:name, :url, :all_events, :enabled, events: [])
end
end

عرض الملف

@@ -1,9 +1,9 @@
module ApplicationHelper
def format_delivery_details(server, text)
text.gsub!(/\<msg\:(\d+)\>/) do
id = $1.to_i
link_to("message ##{id}", organization_server_message_path(server.organization, server, id), :class => "u-link")
text.gsub!(/<msg:(\d+)>/) do
id = ::Regexp.last_match(1).to_i
link_to("message ##{id}", organization_server_message_path(server.organization, server, id), class: "u-link")
end
text.html_safe
end
@@ -29,7 +29,7 @@ module ApplicationHelper
unless server_domains.empty?
s << "<optgroup label='Server Domains'>"
for domain in server_domains
selected = domain == selected_domain ? "selected='selected'" : ''
selected = domain == selected_domain ? "selected='selected'" : ""
s << "<option value='#{domain.id}' #{selected}>#{domain.name}</option>"
end
s << "</optgroup>"
@@ -39,12 +39,11 @@ module ApplicationHelper
unless organization_domains.empty?
s << "<optgroup label='Organization Domains'>"
for domain in organization_domains
selected = domain == selected_domain ? "selected='selected'" : ''
selected = domain == selected_domain ? "selected='selected'" : ""
s << "<option value='#{domain.id}' #{selected}>#{domain.name}</option>"
end
s << "</optgroup>"
end
end.html_safe
end
@@ -57,19 +56,18 @@ module ApplicationHelper
s << "<optgroup label='HTTP Endpoints'>"
for endpoint in http_endpoints
value = "#{endpoint.class}##{endpoint.uuid}"
selected = value == selected_value ? "selected='selected'" : ''
selected = value == selected_value ? "selected='selected'" : ""
s << "<option value='#{value}' #{selected}>#{endpoint.description}</option>"
end
s << "</optgroup>"
end
smtp_endpoints = server.smtp_endpoints.order(:name).to_a
if smtp_endpoints.present?
s << "<optgroup label='SMTP Endpoints'>"
for endpoint in smtp_endpoints
value = "#{endpoint.class}##{endpoint.uuid}"
selected = value == selected_value ? "selected='selected'" : ''
selected = value == selected_value ? "selected='selected'" : ""
s << "<option value='#{value}' #{selected}>#{endpoint.description}</option>"
end
s << "</optgroup>"
@@ -80,7 +78,7 @@ module ApplicationHelper
s << "<optgroup label='Address Endpoints'>"
for endpoint in address_endpoints
value = "#{endpoint.class}##{endpoint.uuid}"
selected = value == selected_value ? "selected='selected'" : ''
selected = value == selected_value ? "selected='selected'" : ""
s << "<option value='#{value}' #{selected}>#{endpoint.address}</option>"
end
s << "</optgroup>"
@@ -89,14 +87,14 @@ module ApplicationHelper
unless options[:other] == false
s << "<optgroup label='Other Options'>"
Route::MODES.each do |mode|
next if mode == 'Endpoint'
selected = (selected_value == mode ? "selected='selected'" : '')
next if mode == "Endpoint"
selected = (selected_value == mode ? "selected='selected'" : "")
text = t("route_modes.#{mode.underscore}")
s << "<option value='#{mode}' #{selected}>#{text}</option>"
end
s << "</optgroup>"
end
end.html_safe
end

عرض الملف

@@ -1,6 +1,7 @@
class ActionDeletionJob < Postal::Job
def perform
object = params['type'].constantize.deleted.find_by_id(params['id'])
object = params["type"].constantize.deleted.find_by_id(params["id"])
if object
log "Deleting #{params['type']}##{params['id']}"
object.destroy
@@ -9,4 +10,5 @@ class ActionDeletionJob < Postal::Job
log "Couldn't find deleted object #{params['type']}##{params['id']}"
end
end
end

عرض الملف

@@ -1,4 +1,5 @@
class ActionDeletionsJob < Postal::Job
def perform
Organization.deleted.each do |org|
log "Permanently removing organization #{org.id} (#{org.permalink})"
@@ -10,4 +11,5 @@ class ActionDeletionsJob < Postal::Job
server.destroy
end
end
end

عرض الملف

@@ -1,6 +1,7 @@
class CheckAllDNSJob < Postal::Job
def perform
Domain.where.not(:dns_checked_at => nil).where("dns_checked_at <= ?", 1.hour.ago).each do |domain|
Domain.where.not(dns_checked_at: nil).where("dns_checked_at <= ?", 1.hour.ago).each do |domain|
log "Checking DNS for domain: #{domain.name}"
domain.check_dns(:auto)
end
@@ -10,4 +11,5 @@ class CheckAllDNSJob < Postal::Job
domain.check_dns
end
end
end

عرض الملف

@@ -1,7 +1,9 @@
require 'authie/session'
require "authie/session"
class CleanupAuthieSessionsJob < Postal::Job
def perform
Authie::Session.cleanup
end
end

عرض الملف

@@ -1,12 +1,14 @@
class ExpireHeldMessagesJob < Postal::Job
def perform
Server.all.each do |server|
messages = server.message_db.messages(:where => {
:status => 'Held',
:hold_expiry => {:less_than => Time.now.to_f}
messages = server.message_db.messages(where: {
status: "Held",
hold_expiry: { less_than: Time.now.to_f }
})
messages.each(&:cancel_hold)
end
end
end

عرض الملف

@@ -1,4 +1,5 @@
class ProcessMessageRetentionJob < Postal::Job
def perform
Server.all.each do |server|
if server.raw_message_retention_days
@@ -18,4 +19,5 @@ class ProcessMessageRetentionJob < Postal::Job
end
end
end
end

عرض الملف

@@ -1,8 +1,10 @@
class PruneSuppressionListsJob < Postal::Job
def perform
Server.all.each do |s|
log "Pruning suppression lists for server #{s.id}"
s.message_db.suppression_list.prune
end
end
end

عرض الملف

@@ -1,8 +1,10 @@
class PruneWebhookRequestsJob < Postal::Job
def perform
Server.all.each do |s|
log "Pruning webhook requests for server #{s.id}"
s.message_db.webhooks.prune
end
end
end

عرض الملف

@@ -1,5 +1,7 @@
class RequeueWebhooksJob < Postal::Job
def perform
WebhookRequest.requeue_all
end
end

عرض الملف

@@ -1,5 +1,7 @@
class SendNotificationsJob < Postal::Job
def perform
Server.send_send_limit_notifications
end
end

عرض الملف

@@ -1,25 +1,25 @@
class SendWebhookJob < Postal::Job
def perform
if server = Server.find(params['server_id'])
if server = Server.find(params["server_id"])
new_items = {}
if params['payload']
for key, value in params['payload']
if key.to_s =~ /\A\_(\w+)/
if params["payload"]
for key, value in params["payload"]
next unless key.to_s =~ /\A_(\w+)/
begin
new_items[$1] = server.message_db.message(value.to_i).webhook_hash
new_items[::Regexp.last_match(1)] = server.message_db.message(value.to_i).webhook_hash
rescue Postal::MessageDB::Message::NotFound
end
end
end
end
new_items.each do |key, value|
params['payload'].delete("_#{key}")
params['payload'][key] = value
params["payload"].delete("_#{key}")
params["payload"][key] = value
end
WebhookRequest.trigger(server, params['event'], params['payload'])
WebhookRequest.trigger(server, params["event"], params["payload"])
else
log "Couldn't find server with ID #{params['server_id']}"
end

عرض الملف

@@ -1,5 +1,7 @@
class SleepJob < Postal::Job
def perform
sleep 5
end
end

عرض الملف

@@ -1,7 +1,6 @@
class TidyRawMessagesJob < Postal::Job
def perform
end
end

عرض الملف

@@ -1,6 +1,7 @@
class UnqueueMessageJob < Postal::Job
def perform
if original_message = QueuedMessage.find_by_id(params['id'])
if original_message = QueuedMessage.find_by_id(params["id"])
if original_message.acquire_lock
log "Lock acquired for queued message #{original_message.id}"
@@ -22,7 +23,7 @@ class UnqueueMessageJob < Postal::Job
begin
other_messages = original_message.batchable_messages(100)
log "Found #{other_messages.size} associated messages to process at the same time (batch key: #{original_message.batch_key})"
rescue
rescue StandardError
original_message.unlock
raise
end
@@ -45,7 +46,7 @@ class UnqueueMessageJob < Postal::Job
#
if queued_message.server.suspended?
log "#{log_prefix} Server is suspended. Holding message."
queued_message.message.create_delivery('Held', :details => "Mail server has been suspended. No e-mails can be processed at present. Contact support for assistance.")
queued_message.message.create_delivery("Held", details: "Mail server has been suspended. No e-mails can be processed at present. Contact support for assistance.")
queued_message.destroy
next
end
@@ -53,19 +54,19 @@ class UnqueueMessageJob < Postal::Job
# We might not be able to send this any more, check the attempts
if queued_message.attempts >= Postal.config.general.maximum_delivery_attempts
details = "Maximum number of delivery attempts (#{queued_message.attempts}) has been reached."
if queued_message.message.scope == 'incoming'
if queued_message.message.scope == "incoming"
# Send bounces to incoming e-mails when they are hard failed
if bounce_id = queued_message.send_bounce
details += " Bounce sent to sender (see message <msg:#{bounce_id}>)"
end
elsif queued_message.message.scope == 'outgoing'
elsif queued_message.message.scope == "outgoing"
# Add the recipient to the suppression list
if queued_message.server.message_db.suppression_list.add(:recipient, queued_message.message.rcpt_to, :reason => "too many soft fails")
if queued_message.server.message_db.suppression_list.add(:recipient, queued_message.message.rcpt_to, reason: "too many soft fails")
log "Added #{queued_message.message.rcpt_to} to suppression list because maximum attempts has been reached"
details += " Added #{queued_message.message.rcpt_to} to suppression list because delivery has failed #{queued_message.attempts} times."
end
end
queued_message.message.create_delivery('HardFail', :details => details)
queued_message.message.create_delivery("HardFail", details: details)
queued_message.destroy
log "#{log_prefix} Message has reached maximum number of attempts. Hard failing."
next
@@ -74,15 +75,15 @@ class UnqueueMessageJob < Postal::Job
# If the raw message has been removed (removed by retention)
unless queued_message.message.raw_message?
log "#{log_prefix} Raw message has been removed. Not sending."
queued_message.message.create_delivery('HardFail', :details => "Raw message has been removed. Cannot send message.")
queued_message.message.create_delivery("HardFail", details: "Raw message has been removed. Cannot send message.")
queued_message.destroy
next
end
#
# Handle Incoming Messages
#  Handle Incoming Messages
#
if queued_message.message.scope == 'incoming'
if queued_message.message.scope == "incoming"
#
# If this is a bounce, we need to handle it as such
#
@@ -91,8 +92,8 @@ class UnqueueMessageJob < Postal::Job
original_messages = queued_message.message.original_messages
unless original_messages.empty?
for original_message in queued_message.message.original_messages
queued_message.message.update(:bounce_for_id => original_message.id, :domain_id => original_message.domain_id)
queued_message.message.create_delivery('Processed', :details => "This has been detected as a bounce message for <msg:#{original_message.id}>.")
queued_message.message.update(bounce_for_id: original_message.id, domain_id: original_message.domain_id)
queued_message.message.create_delivery("Processed", details: "This has been detected as a bounce message for <msg:#{original_message.id}>.")
original_message.bounce!(queued_message.message)
log "#{log_prefix} Bounce linked with message #{original_message.id}"
end
@@ -101,11 +102,11 @@ class UnqueueMessageJob < Postal::Job
end
# This message was sent to the return path but hasn't been matched
# to an original message. If we have a route for this, route it
# otherwise we'll drop at this point.
#  to an original message. If we have a route for this, route it
#  otherwise we'll drop at this point.
if queued_message.message.route_id.nil?
log "#{log_prefix} No source messages found. Hard failing."
queued_message.message.create_delivery('HardFail', :details => "This message was a bounce but we couldn't link it with any outgoing message and there was no route for it.")
queued_message.message.create_delivery("HardFail", details: "This message was a bounce but we couldn't link it with any outgoing message and there was no route for it.")
queued_message.destroy
next
end
@@ -124,7 +125,7 @@ class UnqueueMessageJob < Postal::Job
queued_message.message.inspect_message
if queued_message.message.inspected == 1
is_spam = queued_message.message.spam_score > queued_message.server.spam_threshold
queued_message.message.update(:spam => 1) if is_spam
queued_message.message.update(spam: 1) if is_spam
queued_message.message.append_headers(
"X-Postal-Spam: #{queued_message.message.spam == 1 ? 'yes' : 'no'}",
"X-Postal-Spam-Threshold: #{queued_message.server.spam_threshold}",
@@ -140,15 +141,15 @@ class UnqueueMessageJob < Postal::Job
#
if queued_message.message.spam_score >= queued_message.server.spam_failure_threshold
log "#{log_prefix} Message has a spam score higher than the server's maxmimum. Hard failing."
queued_message.message.create_delivery('HardFail', :details => "Message's spam score is higher than the failure threshold for this server. Threshold is currently #{queued_message.server.spam_failure_threshold}.")
queued_message.message.create_delivery("HardFail", details: "Message's spam score is higher than the failure threshold for this server. Threshold is currently #{queued_message.server.spam_failure_threshold}.")
queued_message.destroy
next
end
# If the server is in development mode, hold it
if queued_message.server.mode == 'Development' && !queued_message.manual?
if queued_message.server.mode == "Development" && !queued_message.manual?
log "Server is in development mode so holding."
queued_message.message.create_delivery('Held', :details => "Server is in development mode.")
queued_message.message.create_delivery("Held", details: "Server is in development mode.")
queued_message.destroy
log "#{log_prefix} Server is in development mode. Holding."
next
@@ -161,16 +162,16 @@ class UnqueueMessageJob < Postal::Job
if route = queued_message.message.route
# If the route says we're holding quananteed mail and this is spam, we'll hold this
if route.spam_mode == 'Quarantine' && queued_message.message.spam == 1 && !queued_message.manual?
queued_message.message.create_delivery('Held', :details => "Message placed into quarantine.")
if route.spam_mode == "Quarantine" && queued_message.message.spam == 1 && !queued_message.manual?
queued_message.message.create_delivery("Held", details: "Message placed into quarantine.")
queued_message.destroy
log "#{log_prefix} Route says to quarantine spam message. Holding."
next
end
# If the route says we're holding quananteed mail and this is spam, we'll hold this
if route.spam_mode == 'Fail' && queued_message.message.spam == 1 && !queued_message.manual?
queued_message.message.create_delivery('HardFail', :details => "Message is spam and the route specifies it should be failed.")
if route.spam_mode == "Fail" && queued_message.message.spam == 1 && !queued_message.manual?
queued_message.message.create_delivery("HardFail", details: "Message is spam and the route specifies it should be failed.")
queued_message.destroy
log "#{log_prefix} Route says to fail spam message. Hard failing."
next
@@ -179,8 +180,8 @@ class UnqueueMessageJob < Postal::Job
#
# Messages that should be blindly accepted are blindly accepted
#
if route.mode == 'Accept'
queued_message.message.create_delivery('Processed', :details => "Message has been accepted but not sent to any endpoints.")
if route.mode == "Accept"
queued_message.message.create_delivery("Processed", details: "Message has been accepted but not sent to any endpoints.")
queued_message.destroy
log "#{log_prefix} Route says to accept without endpoint. Marking as processed."
next
@@ -189,14 +190,14 @@ class UnqueueMessageJob < Postal::Job
#
# Messages that should be accepted and held should be held
#
if route.mode == 'Hold'
if route.mode == "Hold"
log "#{log_prefix} Route says to hold message."
if queued_message.manual?
log "#{log_prefix} Message was queued manually. Marking as processed."
queued_message.message.create_delivery('Processed', :details => "Message has been processed.")
queued_message.message.create_delivery("Processed", details: "Message has been processed.")
else
log "#{log_prefix} Message was not queued manually. Holding."
queued_message.message.create_delivery('Held', :details => "Message has been accepted but not sent to any endpoints.")
queued_message.message.create_delivery("Held", details: "Message has been accepted but not sent to any endpoints.")
end
queued_message.destroy
next
@@ -205,29 +206,28 @@ class UnqueueMessageJob < Postal::Job
#
# Messages that should be bounced should be bounced (or rejected if they got this far)
#
if route.mode == 'Bounce' || route.mode == 'Reject'
if route.mode == "Bounce" || route.mode == "Reject"
if id = queued_message.send_bounce
queued_message.message.create_delivery('HardFail', :details => "Message has been bounced because the route asks for this. See message <msg:#{id}>")
queued_message.message.create_delivery("HardFail", details: "Message has been bounced because the route asks for this. See message <msg:#{id}>")
log "#{log_prefix} Route says to bounce. Hard failing and sent bounce (#{id})."
end
queued_message.destroy
next
end
begin
if @fixed_result
result = @fixed_result
else
case queued_message.message.endpoint
when SMTPEndpoint
sender = cached_sender(Postal::SMTPSender, queued_message.message.recipient_domain, nil, :servers => [queued_message.message.endpoint])
sender = cached_sender(Postal::SMTPSender, queued_message.message.recipient_domain, nil, servers: [queued_message.message.endpoint])
when HTTPEndpoint
sender = cached_sender(Postal::HTTPSender, queued_message.message.endpoint)
when AddressEndpoint
sender = cached_sender(Postal::SMTPSender, queued_message.message.endpoint.domain, nil, :force_rcpt_to => queued_message.message.endpoint.address)
sender = cached_sender(Postal::SMTPSender, queued_message.message.endpoint.domain, nil, force_rcpt_to: queued_message.message.endpoint.address)
else
log "#{log_prefix} Invalid endpoint for route (#{queued_message.message.endpoint_type})"
queued_message.message.create_delivery('HardFail', :details => "Invalid endpoint for route.")
queued_message.message.create_delivery("HardFail", details: "Invalid endpoint for route.")
queued_message.destroy
next
end
@@ -236,14 +236,13 @@ class UnqueueMessageJob < Postal::Job
@fixed_result = result
end
end
end
# Log the result
log_details = result.details
if result.type =='HardFail' && result.suppress_bounce
if result.type == "HardFail" && result.suppress_bounce
# The delivery hard failed, but requested that no bounce be sent
log "#{log_prefix} Suppressing bounce message after hard fail"
elsif result.type =='HardFail' && queued_message.message.send_bounces?
elsif result.type == "HardFail" && queued_message.message.send_bounces?
# If the message is a hard fail, send a bounce message for this message.
log "#{log_prefix} Sending a bounce because message hard failed"
if bounce_id = queued_message.send_bounce
@@ -252,7 +251,7 @@ class UnqueueMessageJob < Postal::Job
end
end
queued_message.message.create_delivery(result.type, :details => log_details, :output => result.output&.strip, :sent_with_ssl => result.secure, :log_id => result.log_id, :time => result.time)
queued_message.message.create_delivery(result.type, details: log_details, output: result.output&.strip, sent_with_ssl: result.secure, log_id: result.log_id, time: result.time)
if result.retry
log "#{log_prefix} Message requeued for trying later."
@@ -266,7 +265,7 @@ class UnqueueMessageJob < Postal::Job
end
else
log "#{log_prefix} No route and/or endpoint available for processing. Hard failing."
queued_message.message.create_delivery('HardFail', :details => "Message does not have a route and/or endpoint available for delivery.")
queued_message.message.create_delivery("HardFail", details: "Message does not have a route and/or endpoint available for delivery.")
queued_message.destroy
next
end
@@ -275,10 +274,10 @@ class UnqueueMessageJob < Postal::Job
#
# Handle Outgoing Messages
#
if queued_message.message.scope == 'outgoing'
if queued_message.message.scope == "outgoing"
if queued_message.message.domain.nil?
log "#{log_prefix} Message has no domain. Hard failing."
queued_message.message.create_delivery('HardFail', :details => "Message's domain no longer exist")
queued_message.message.create_delivery("HardFail", details: "Message's domain no longer exist")
queued_message.destroy
next
end
@@ -288,7 +287,7 @@ class UnqueueMessageJob < Postal::Job
#
if queued_message.message.rcpt_to.blank?
log "#{log_prefix} Message has no to address. Hard failing."
queued_message.message.create_delivery('HardFail', :details => "Message doesn't have an RCPT to")
queued_message.message.create_delivery("HardFail", details: "Message doesn't have an RCPT to")
queued_message.destroy
next
end
@@ -298,7 +297,7 @@ class UnqueueMessageJob < Postal::Job
#
if !queued_message.manual? && queued_message.message.credential && queued_message.message.credential.hold?
log "#{log_prefix} Credential wants us to hold messages. Holding."
queued_message.message.create_delivery('Held', :details => "Credential is configured to hold all messages authenticated by it.")
queued_message.message.create_delivery("Held", details: "Credential is configured to hold all messages authenticated by it.")
queued_message.destroy
next
end
@@ -308,15 +307,15 @@ class UnqueueMessageJob < Postal::Job
#
if !queued_message.manual? && sl = queued_message.server.message_db.suppression_list.get(:recipient, queued_message.message.rcpt_to)
log "#{log_prefix} Recipient is on the suppression list. Holding."
queued_message.message.create_delivery('Held', :details => "Recipient (#{queued_message.message.rcpt_to}) is on the suppression list (reason: #{sl['reason']})")
queued_message.message.create_delivery("Held", details: "Recipient (#{queued_message.message.rcpt_to}) is on the suppression list (reason: #{sl['reason']})")
queued_message.destroy
next
end
# Extract a tag and add it to the message if one doesn't exist
if queued_message.message.tag.nil? && tag = queued_message.message.headers['x-postal-tag']
if queued_message.message.tag.nil? && tag = queued_message.message.headers["x-postal-tag"]
log "#{log_prefix} Added tag #{tag.last}"
queued_message.message.update(:tag => tag.last)
queued_message.message.update(tag: tag.last)
end
# Parse the content of the message as appropriate
@@ -331,53 +330,53 @@ class UnqueueMessageJob < Postal::Job
queued_message.message.inspect_message
if queued_message.message.inspected == 1
if queued_message.message.spam_score >= queued_message.server.outbound_spam_threshold
queued_message.message.update(:spam => 1)
queued_message.message.update(spam: 1)
end
log "#{log_prefix} Message inspected successfully"
end
end
if queued_message.message.spam == 1
queued_message.message.create_delivery("HardFail", :details => "Message is likely spam. Threshold is #{queued_message.server.outbound_spam_threshold} and the message scored #{queued_message.message.spam_score}.")
queued_message.message.create_delivery("HardFail", details: "Message is likely spam. Threshold is #{queued_message.server.outbound_spam_threshold} and the message scored #{queued_message.message.spam_score}.")
queued_message.destroy
log "#{log_prefix} Message is spam (#{queued_message.message.spam_score}). Hard failing."
next
end
# Add outgoing headers
if !queued_message.message.has_outgoing_headers?
unless queued_message.message.has_outgoing_headers?
queued_message.message.add_outgoing_headers
end
# Check send limits
if queued_message.server.send_limit_exceeded?
# If we're over the limit, we're going to be holding this message
queued_message.server.update_columns(:send_limit_exceeded_at => Time.now, :send_limit_approaching_at => nil)
queued_message.message.create_delivery('Held', :details => "Message held because send limit (#{queued_message.server.send_limit}) has been reached.")
queued_message.server.update_columns(send_limit_exceeded_at: Time.now, send_limit_approaching_at: nil)
queued_message.message.create_delivery("Held", details: "Message held because send limit (#{queued_message.server.send_limit}) has been reached.")
queued_message.destroy
log "#{log_prefix} Server send limit has been exceeded. Holding."
next
elsif queued_message.server.send_limit_approaching?
# If we're approaching the limit, just say we are but continue to process the message
queued_message.server.update_columns(:send_limit_approaching_at => Time.now, :send_limit_exceeded_at => nil)
queued_message.server.update_columns(send_limit_approaching_at: Time.now, send_limit_exceeded_at: nil)
else
queued_message.server.update_columns(:send_limit_approaching_at => nil, :send_limit_exceeded_at => nil)
queued_message.server.update_columns(send_limit_approaching_at: nil, send_limit_exceeded_at: nil)
end
# Update the live stats for this message.
queued_message.message.database.live_stats.increment(queued_message.message.scope)
# If the server is in development mode, hold it
if queued_message.server.mode == 'Development' && !queued_message.manual?
if queued_message.server.mode == "Development" && !queued_message.manual?
log "Server is in development mode so holding."
queued_message.message.create_delivery('Held', :details => "Server is in development mode.")
queued_message.message.create_delivery("Held", details: "Server is in development mode.")
queued_message.destroy
log "#{log_prefix} Server is in development mode. Holding."
next
end
# Send the outgoing message to the SMTP sender
begin
if @fixed_result
result = @fixed_result
else
@@ -387,36 +386,31 @@ class UnqueueMessageJob < Postal::Job
@fixed_result = result
end
end
end
#
# If the message has been hard failed, check to see how many other recent hard fails we've had for the address
# and if there are more than 2, suppress the address for 30 days.
#
if result.type == 'HardFail'
recent_hard_fails = queued_message.server.message_db.select(:messages, :where => {:rcpt_to => queued_message.message.rcpt_to, :status => 'HardFail', :timestamp => {:greater_than => 24.hours.ago.to_f}}, :count => true)
if recent_hard_fails >= 1
if queued_message.server.message_db.suppression_list.add(:recipient, queued_message.message.rcpt_to, :reason => "too many hard fails")
if result.type == "HardFail"
recent_hard_fails = queued_message.server.message_db.select(:messages, where: { rcpt_to: queued_message.message.rcpt_to, status: "HardFail", timestamp: { greater_than: 24.hours.ago.to_f } }, count: true)
if recent_hard_fails >= 1 && queued_message.server.message_db.suppression_list.add(:recipient, queued_message.message.rcpt_to, reason: "too many hard fails")
log "#{log_prefix} Added #{queued_message.message.rcpt_to} to suppression list because #{recent_hard_fails} hard fails in 24 hours"
result.details += "." if result.details =~ /\.\z/
result.details += " Recipient added to suppression list (too many hard fails)."
end
end
end
#
# If a message is sent successfully, remove the users from the suppression list
#
if result.type == 'Sent'
if queued_message.server.message_db.suppression_list.remove(:recipient, queued_message.message.rcpt_to)
if result.type == "Sent" && queued_message.server.message_db.suppression_list.remove(:recipient, queued_message.message.rcpt_to)
log "#{log_prefix} Removed #{queued_message.message.rcpt_to} from suppression list because success"
result.details += "." if result.details =~ /\.\z/
result.details += " Recipient removed from suppression list."
end
end
# Log the result
queued_message.message.create_delivery(result.type, :details => result.details, :output => result.output, :sent_with_ssl => result.secure, :log_id => result.log_id, :time => result.time)
queued_message.message.create_delivery(result.type, details: result.details, output: result.output, sent_with_ssl: result.secure, log_id: result.log_id, time: result.time)
if result.retry
log "#{log_prefix} Message requeued for trying later."
queued_message.retry_later(result.retry.is_a?(Integer) ? result.retry : nil)
@@ -425,17 +419,16 @@ class UnqueueMessageJob < Postal::Job
queued_message.destroy
end
end
rescue => e
rescue StandardError => e
log "#{log_prefix} Internal error: #{e.class}: #{e.message}"
e.backtrace.each { |e| log("#{log_prefix} #{e}") }
queued_message.retry_later
log "#{log_prefix} Queued message was unlocked"
if defined?(Raven)
Raven.capture_exception(e, :extra => {:job_id => self.id, :server_id => queued_message.server_id, :message_id => queued_message.message_id})
Raven.capture_exception(e, extra: { job_id: self.id, server_id: queued_message.server_id, message_id: queued_message.message_id })
end
if queued_message.message
queued_message.message.create_delivery("Error", :details => "An internal error occurred while sending this message. This message will be retried automatically. If this persists, contact support for assistance.", :output => "#{e.class}: #{e.message}", :log_id => "J-#{self.id}")
queued_message.message.create_delivery("Error", details: "An internal error occurred while sending this message. This message will be retried automatically. If this persists, contact support for assistance.", output: "#{e.class}: #{e.message}", log_id: "J-#{self.id}")
end
end
end
@@ -447,7 +440,11 @@ class UnqueueMessageJob < Postal::Job
log "No queued message with ID #{params['id']} was available for processing."
end
ensure
@sender&.finish rescue nil
begin
@sender&.finish
rescue StandardError
nil
end
end
private
@@ -459,4 +456,5 @@ class UnqueueMessageJob < Postal::Job
sender
end
end
end

عرض الملف

@@ -1,6 +1,7 @@
class WebhookDeliveryJob < Postal::Job
def perform
if webhook_request = WebhookRequest.find_by_id(params['id'])
if webhook_request = WebhookRequest.find_by_id(params["id"])
if webhook_request.deliver
log "Succesfully delivered"
else
@@ -10,4 +11,5 @@ class WebhookDeliveryJob < Postal::Job
log "No webhook request found with ID '#{params['id']}'"
end
end
end

عرض الملف

@@ -2,50 +2,50 @@ class AppMailer < ApplicationMailer
def verify_email_address(user)
@user = user
mail :to => @user.email_address, :subject => "Verify your new e-mail address"
mail to: @user.email_address, subject: "Verify your new e-mail address"
end
def new_user(user)
@user = user
mail :to => @user.email_address, :subject => "Welcome to Postal"
mail to: @user.email_address, subject: "Welcome to Postal"
end
def user_invite(user_invite, organization)
@user_invite = user_invite
@organization = organization
mail :to => @user_invite.email_address, :subject => "Access the #{organization.name} organization on Postal"
mail to: @user_invite.email_address, subject: "Access the #{organization.name} organization on Postal"
end
def verify_domain(domain, email_address, user)
@domain = domain
@email_address = email_address
@user = user
mail :to => email_address, :subject => "Verify your ownership of #{@domain.name}"
mail to: email_address, subject: "Verify your ownership of #{@domain.name}"
end
def password_reset(user, return_to = nil)
@user = user
@return_to = return_to
mail :to => @user.email_address, :subject => "Reset your Postal password"
mail to: @user.email_address, subject: "Reset your Postal password"
end
def server_send_limit_approaching(server)
@server = server
mail :to => @server.organization.notification_addresses, :subject => "[#{server.full_permalink}] Mail server is approaching its send limit"
mail to: @server.organization.notification_addresses, subject: "[#{server.full_permalink}] Mail server is approaching its send limit"
end
def server_send_limit_exceeded(server)
@server = server
mail :to => @server.organization.notification_addresses, :subject => "[#{server.full_permalink}] Mail server has exceeded its send limit"
mail to: @server.organization.notification_addresses, subject: "[#{server.full_permalink}] Mail server has exceeded its send limit"
end
def server_suspended(server)
@server = server
mail :to => @server.organization.notification_addresses, :subject => "[#{server.full_permalink}] Your mail server has been suspended"
mail to: @server.organization.notification_addresses, subject: "[#{server.full_permalink}] Your mail server has been suspended"
end
def test_message(recipient)
mail :to => recipient, :subject => "Postal SMTP Test Message"
mail to: recipient, subject: "Postal SMTP Test Message"
end
end

عرض الملف

@@ -1,4 +1,6 @@
class ApplicationMailer < ActionMailer::Base
default :from => "#{Postal.smtp_from_name} <#{Postal.smtp_from_address}>"
default from: "#{Postal.smtp_from_name} <#{Postal.smtp_from_address}>"
layout false
end

عرض الملف

@@ -13,22 +13,21 @@
class AdditionalRouteEndpoint < ApplicationRecord
belongs_to :route
belongs_to :endpoint, :polymorphic => true
belongs_to :endpoint, polymorphic: true
validate :validate_endpoint_belongs_to_server
validate :validate_wildcard
validate :validate_uniqueness
def self.find_by_endpoint(endpoint)
class_name, id = endpoint.split('#', 2)
class_name, id = endpoint.split("#", 2)
unless Route::ENDPOINT_TYPES.include?(class_name)
raise Postal::Error, "Invalid endpoint class name '#{class_name}'"
end
if uuid = class_name.constantize.find_by_uuid(id)
where(:endpoint_type => class_name, :endpoint_id => uuid).first
else
nil
end
return unless uuid = class_name.constantize.find_by_uuid(id)
where(endpoint_type: class_name, endpoint_id: uuid).first
end
def _endpoint
@@ -38,39 +37,37 @@ class AdditionalRouteEndpoint < ApplicationRecord
def _endpoint=(value)
if value.blank?
self.endpoint = nil
else
if value =~ /\#/
class_name, id = value.split('#', 2)
elsif value =~ /\#/
class_name, id = value.split("#", 2)
unless Route::ENDPOINT_TYPES.include?(class_name)
raise Postal::Error, "Invalid endpoint class name '#{class_name}'"
end
self.endpoint = class_name.constantize.find_by_uuid(id)
else
self.endpoint = nil
end
end
end
private
def validate_endpoint_belongs_to_server
if self.endpoint && self.endpoint&.server != self.route.server
return unless endpoint && endpoint&.server != route.server
errors.add :endpoint, :invalid
end
end
def validate_uniqueness
if self.endpoint == self.route.endpoint
return unless endpoint == route.endpoint
errors.add :base, "You can only add an endpoint to a route once"
end
end
def validate_wildcard
if self.route.wildcard?
if self.endpoint_type == 'SMTPEndpoint' || self.endpoint_type == 'AddressEndpoint'
return unless route.wildcard?
return unless endpoint_type == "SMTPEndpoint" || endpoint_type == "AddressEndpoint"
errors.add :base, "SMTP or address endpoints are not permitted on wildcard routes"
end
end
end
end

عرض الملف

@@ -16,10 +16,10 @@ class AddressEndpoint < ApplicationRecord
include HasUUID
belongs_to :server
has_many :routes, :as => :endpoint
has_many :additional_route_endpoints, :dependent => :destroy, :as => :endpoint
has_many :routes, as: :endpoint
has_many :additional_route_endpoints, dependent: :destroy, as: :endpoint
validates :address, :presence => true, :format => {:with => /@/}, :uniqueness => {:scope => [:server_id], :message => "has already been added"}
validates :address, presence: true, format: { with: /@/ }, uniqueness: { scope: [:server_id], message: "has already been added" }
before_destroy :update_routes
@@ -28,15 +28,15 @@ class AddressEndpoint < ApplicationRecord
end
def update_routes
self.routes.each { |r| r.update(:endpoint => nil, :mode => 'Reject') }
routes.each { |r| r.update(endpoint: nil, mode: "Reject") }
end
def description
self.address
address
end
def domain
address.split('@', 2).last
address.split("@", 2).last
end
end

عرض الملف

@@ -1,5 +1,7 @@
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
self.inheritance_column = 'sti_type'
self.inheritance_column = "sti_type"
nilify_blanks
end

عرض الملف

@@ -5,7 +5,7 @@ module HasMessage
end
def message
@message ||= self.server.message_db.message(self.message_id)
@message ||= server.message_db.message(message_id)
end
def message=(message)
@@ -14,6 +14,7 @@ module HasMessage
end
module ClassMethods
def include_message
queued_messages = all.to_a
server_ids = queued_messages.map(&:server_id).uniq
@@ -22,10 +23,11 @@ module HasMessage
elsif server_ids.size > 1
raise Postal::Error, "'include_message' can only be used on collections of messages from the same server"
end
message_ids = queued_messages.map(&:message_id).uniq
server = queued_messages.first&.server
messages = server.message_db.messages(:where => {:id => message_ids}).each_with_object({}) do |message, hash|
hash[message.id] = message
messages = server.message_db.messages(where: { id: message_ids }).index_by do |message|
message.id
end
queued_messages.each do |queued_message|
if m = messages[queued_message.message_id]
@@ -33,6 +35,7 @@ module HasMessage
end
end
end
end
end

عرض الملف

@@ -3,16 +3,16 @@ module HasSoftDestroy
def self.included(base)
base.define_callbacks :soft_destroy
base.class_eval do
scope :deleted, -> { where.not(:deleted_at => nil) }
scope :present, -> { where(:deleted_at => nil) }
scope :deleted, -> { where.not(deleted_at: nil) }
scope :present, -> { where(deleted_at: nil) }
end
end
def soft_destroy
run_callbacks :soft_destroy do
self.deleted_at = Time.now
self.save!
ActionDeletionJob.queue(:main, :type => self.class.name, :id => self.id)
save!
ActionDeletionJob.queue(:main, type: self.class.name, id: id)
end
end

عرض الملف

@@ -1,11 +1,13 @@
module HasUUID
def self.included(base)
base.class_eval do
random_string :uuid, :type => :uuid, :unique => true
random_string :uuid, type: :uuid, unique: true
end
end
def to_param
uuid
end
end

عرض الملف

@@ -21,11 +21,11 @@ class Credential < ApplicationRecord
belongs_to :server
TYPES = ['SMTP', 'API', 'SMTP-IP']
TYPES = ["SMTP", "API", "SMTP-IP"]
validates :key, :presence => true, :uniqueness => true
validates :type, :inclusion => {:in => TYPES}
validates :name, :presence => true
validates :key, presence: true, uniqueness: true
validates :type, inclusion: { in: TYPES }
validates :name, presence: true
validate :validate_key_cannot_be_changed
validate :validate_key_for_smtp_ip
@@ -33,10 +33,9 @@ class Credential < ApplicationRecord
before_validation :generate_key
def generate_key
return if self.type == 'SMTP-IP'
return if self.persisted?
return if type == "SMTP-IP"
return if persisted?
self.key = SecureRandomString.new(24)
end
@@ -51,26 +50,26 @@ class Credential < ApplicationRecord
def usage_type
if last_used_at.nil?
'Unused'
"Unused"
elsif last_used_at < 1.year.ago
'Inactive'
"Inactive"
elsif last_used_at < 6.months.ago
'Dormant'
"Dormant"
elsif last_used_at < 1.month.ago
'Quiet'
"Quiet"
else
'Active'
"Active"
end
end
def to_smtp_plain
Base64.encode64("\0XX\0#{self.key}").strip
Base64.encode64("\0XX\0#{key}").strip
end
def ipaddr
return unless type == 'SMTP-IP'
return unless type == "SMTP-IP"
@ipaddr ||= IPAddr.new(self.key)
@ipaddr ||= IPAddr.new(key)
rescue IPAddr::InvalidAddressError
nil
end
@@ -80,15 +79,15 @@ class Credential < ApplicationRecord
def validate_key_cannot_be_changed
return if new_record?
return unless key_changed?
return if type == 'SMTP-IP'
return if type == "SMTP-IP"
errors.add :key, "cannot be changed"
end
def validate_key_for_smtp_ip
return unless type == 'SMTP-IP'
return unless type == "SMTP-IP"
IPAddr.new(self.key.to_s)
IPAddr.new(key.to_s)
rescue IPAddr::InvalidAddressError
errors.add :key, "must be a valid IPv4 or IPv6 address"
end

عرض الملف

@@ -34,39 +34,39 @@
# index_domains_on_uuid (uuid)
#
require 'resolv'
require "resolv"
class Domain < ApplicationRecord
include HasUUID
require_dependency 'domain/dns_checks'
require_dependency 'domain/dns_verification'
require_dependency "domain/dns_checks"
require_dependency "domain/dns_verification"
VERIFICATION_EMAIL_ALIASES = ['webmaster', 'postmaster', 'admin', 'administrator', 'hostmaster']
VERIFICATION_EMAIL_ALIASES = ["webmaster", "postmaster", "admin", "administrator", "hostmaster"]
belongs_to :server, :optional => true
belongs_to :owner, :optional => true, :polymorphic => true
has_many :routes, :dependent => :destroy
has_many :track_domains, :dependent => :destroy
belongs_to :server, optional: true
belongs_to :owner, optional: true, polymorphic: true
has_many :routes, dependent: :destroy
has_many :track_domains, dependent: :destroy
VERIFICATION_METHODS = ['DNS', 'Email']
VERIFICATION_METHODS = ["DNS", "Email"]
validates :name, :presence => true, :format => {:with => /\A[a-z0-9\-\.]*\z/}, :uniqueness => {:scope => [:owner_type, :owner_id], :message => "is already added"}
validates :verification_method, :inclusion => {:in => VERIFICATION_METHODS}
validates :name, presence: true, format: { with: /\A[a-z0-9\-.]*\z/ }, uniqueness: { scope: [:owner_type, :owner_id], message: "is already added" }
validates :verification_method, inclusion: { in: VERIFICATION_METHODS }
random_string :dkim_identifier_string, :type => :chars, :length => 6, :unique => true, :upper_letters_only => true
random_string :dkim_identifier_string, type: :chars, length: 6, unique: true, upper_letters_only: true
before_create :generate_dkim_key
scope :verified, -> { where.not(:verified_at => nil) }
scope :verified, -> { where.not(verified_at: nil) }
when_attribute :verification_method, :changes_to => :anything do
when_attribute :verification_method, changes_to: :anything do
before_save do
if self.verification_method == 'DNS'
self.verification_token = Nifty::Utils::RandomString.generate(:length => 32)
elsif self.verification_method == 'Email'
self.verification_token = rand(999999).to_s.ljust(6, '0')
if verification_method == "DNS"
self.verification_token = Nifty::Utils::RandomString.generate(length: 32)
elsif verification_method == "Email"
self.verification_token = rand(999_999).to_s.ljust(6, "0")
else
self.verification_token = nil
end
@@ -79,13 +79,13 @@ class Domain < ApplicationRecord
def verify
self.verified_at = Time.now
self.save!
save!
end
def parent_domains
parts = self.name.split('.')
parts[0,parts.size-1].each_with_index.map do |p, i|
parts[i..-1].join('.')
parts = name.split(".")
parts[0, parts.size - 1].each_with_index.map do |p, i|
parts[i..-1].join(".")
end
end
@@ -94,7 +94,7 @@ class Domain < ApplicationRecord
end
def dkim_key
@dkim_key ||= OpenSSL::PKey::RSA.new(self.dkim_private_key)
@dkim_key ||= OpenSSL::PKey::RSA.new(dkim_private_key)
end
def to_param
@@ -114,12 +114,12 @@ class Domain < ApplicationRecord
end
def dkim_record
public_key = dkim_key.public_key.to_s.gsub(/\-+[A-Z ]+\-+\n/, '').gsub(/\n/, '')
public_key = dkim_key.public_key.to_s.gsub(/-+[A-Z ]+-+\n/, "").gsub(/\n/, "")
"v=DKIM1; t=s; h=sha256; p=#{public_key};"
end
def dkim_identifier
Postal.config.dns.dkim_identifier + "-#{self.dkim_identifier_string}"
Postal.config.dns.dkim_identifier + "-#{dkim_identifier_string}"
end
def dkim_record_name
@@ -127,7 +127,7 @@ class Domain < ApplicationRecord
end
def return_path_domain
"#{Postal.config.dns.custom_return_path_prefix}.#{self.name}"
"#{Postal.config.dns.custom_return_path_prefix}.#{name}"
end
def nameservers
@@ -135,7 +135,7 @@ class Domain < ApplicationRecord
end
def resolver
@resolver ||= Postal.config.general.use_local_ns_for_domains? ? Resolv::DNS.new : Resolv::DNS.new(:nameserver => nameservers)
@resolver ||= Postal.config.general.use_local_ns_for_domains? ? Resolv::DNS.new : Resolv::DNS.new(nameserver: nameservers)
end
private
@@ -143,15 +143,17 @@ class Domain < ApplicationRecord
def get_nameservers
local_resolver = Resolv::DNS.new
ns_records = []
parts = name.split('.')
parts = name.split(".")
(parts.size - 1).times do |n|
d = parts[n, parts.size - n + 1].join('.')
d = parts[n, parts.size - n + 1].join(".")
ns_records = local_resolver.getresources(d, Resolv::DNS::Resource::IN::NS).map { |s| s.name.to_s }
break unless ns_records.blank?
break if ns_records.present?
end
return [] if ns_records.blank?
ns_records = ns_records.map{|r| local_resolver.getresources(r, Resolv::DNS::Resource::IN::A).map { |s| s.address.to_s} }.flatten
ns_records = ns_records.map { |r| local_resolver.getresources(r, Resolv::DNS::Resource::IN::A).map { |s| s.address.to_s } }.flatten
return [] if ns_records.blank?
ns_records
end

عرض الملف

@@ -1,9 +1,9 @@
require 'resolv'
require "resolv"
class Domain
def dns_ok?
spf_status == 'OK' && dkim_status == 'OK' && ['OK', 'Missing'].include?(self.mx_status) && ['OK', 'Missing'].include?(self.return_path_status)
spf_status == "OK" && dkim_status == "OK" && ["OK", "Missing"].include?(mx_status) && ["OK", "Missing"].include?(return_path_status)
end
def dns_checked?
@@ -16,21 +16,21 @@ class Domain
check_mx_records
check_return_path_record
self.dns_checked_at = Time.now
self.save!
if source == :auto && !dns_ok? && self.owner.is_a?(Server)
WebhookRequest.trigger(self.owner, 'DomainDNSError', {
:server => self.owner.webhook_hash,
:domain => self.name,
:uuid => self.uuid,
:dns_checked_at => self.dns_checked_at.to_f,
:spf_status => self.spf_status,
:spf_error => self.spf_error,
:dkim_status => self.dkim_status,
:dkim_error => self.dkim_error,
:mx_status => self.mx_status,
:mx_error => self.mx_error,
:return_path_status => self.return_path_status,
:return_path_error => self.return_path_error
save!
if source == :auto && !dns_ok? && owner.is_a?(Server)
WebhookRequest.trigger(owner, "DomainDNSError", {
server: owner.webhook_hash,
domain: name,
uuid: uuid,
dns_checked_at: dns_checked_at.to_f,
spf_status: spf_status,
spf_error: spf_error,
dkim_status: dkim_status,
dkim_error: dkim_error,
mx_status: mx_status,
mx_error: mx_error,
return_path_status: return_path_status,
return_path_error: return_path_error
})
end
dns_ok?
@@ -41,19 +41,19 @@ class Domain
#
def check_spf_record
result = resolver.getresources(self.name, Resolv::DNS::Resource::IN::TXT)
spf_records = result.map(&:data).select { |d| d =~ /\Av=spf1/}
result = resolver.getresources(name, Resolv::DNS::Resource::IN::TXT)
spf_records = result.map(&:data).select { |d| d =~ /\Av=spf1/ }
if spf_records.empty?
self.spf_status = 'Missing'
self.spf_error = 'No SPF record exists for this domain'
self.spf_status = "Missing"
self.spf_error = "No SPF record exists for this domain"
else
suitable_spf_records = spf_records.select { |d| d =~ /include\:\s*#{Regexp.escape(Postal.config.dns.spf_include)}/}
suitable_spf_records = spf_records.select { |d| d =~ /include:\s*#{Regexp.escape(Postal.config.dns.spf_include)}/ }
if suitable_spf_records.empty?
self.spf_status = 'Invalid'
self.spf_status = "Invalid"
self.spf_error = "An SPF record exists but it doesn't include #{Postal.config.dns.spf_include}"
false
else
self.spf_status = 'OK'
self.spf_status = "OK"
self.spf_error = nil
true
end
@@ -74,18 +74,18 @@ class Domain
result = resolver.getresources(domain, Resolv::DNS::Resource::IN::TXT)
records = result.map(&:data)
if records.empty?
self.dkim_status = 'Missing'
self.dkim_status = "Missing"
self.dkim_error = "No TXT records were returned for #{domain}"
else
sanitised_dkim_record = records.first.strip.ends_with?(';') ? records.first.strip : "#{records.first.strip};"
sanitised_dkim_record = records.first.strip.ends_with?(";") ? records.first.strip : "#{records.first.strip};"
if records.size > 1
self.dkim_status = 'Invalid'
self.dkim_status = "Invalid"
self.dkim_error = "There are #{records.size} records for at #{domain}. There should only be one."
elsif sanitised_dkim_record != self.dkim_record
self.dkim_status = 'Invalid'
elsif sanitised_dkim_record != dkim_record
self.dkim_status = "Invalid"
self.dkim_error = "The DKIM record at #{domain} does not match the record we have provided. Please check it has been copied correctly."
else
self.dkim_status = 'OK'
self.dkim_status = "OK"
self.dkim_error = nil
true
end
@@ -102,21 +102,21 @@ class Domain
#
def check_mx_records
result = resolver.getresources(self.name, Resolv::DNS::Resource::IN::MX)
result = resolver.getresources(name, Resolv::DNS::Resource::IN::MX)
records = result.map(&:exchange)
if records.empty?
self.mx_status = 'Missing'
self.mx_error = "There are no MX records for #{self.name}"
self.mx_status = "Missing"
self.mx_error = "There are no MX records for #{name}"
else
missing_records = Postal.config.dns.mx_records.dup - records.map { |r| r.to_s.downcase }
if missing_records.empty?
self.mx_status = 'OK'
self.mx_status = "OK"
self.mx_error = nil
elsif missing_records.size == Postal.config.dns.mx_records.size
self.mx_status = 'Missing'
self.mx_error = 'You have MX records but none of them point to us.'
self.mx_status = "Missing"
self.mx_error = "You have MX records but none of them point to us."
else
self.mx_status = 'Invalid'
self.mx_status = "Invalid"
self.mx_error = "MX #{missing_records.size == 1 ? 'record' : 'records'} for #{missing_records.to_sentence} are missing and are required."
end
end
@@ -132,19 +132,17 @@ class Domain
#
def check_return_path_record
result = resolver.getresources(self.return_path_domain, Resolv::DNS::Resource::IN::CNAME)
result = resolver.getresources(return_path_domain, Resolv::DNS::Resource::IN::CNAME)
records = result.map { |r| r.name.to_s.downcase }
if records.empty?
self.return_path_status = 'Missing'
self.return_path_error = "There is no return path record at #{self.return_path_domain}"
else
if records.size == 1 && records.first == Postal.config.dns.return_path
self.return_path_status = 'OK'
self.return_path_status = "Missing"
self.return_path_error = "There is no return path record at #{return_path_domain}"
elsif records.size == 1 && records.first == Postal.config.dns.return_path
self.return_path_status = "OK"
self.return_path_error = nil
else
self.return_path_status = 'Invalid'
self.return_path_error = "There is a CNAME record at #{self.return_path_domain} but it points to #{records.first} which is incorrect. It should point to #{Postal.config.dns.return_path}."
end
self.return_path_status = "Invalid"
self.return_path_error = "There is a CNAME record at #{return_path_domain} but it points to #{records.first} which is incorrect. It should point to #{Postal.config.dns.return_path}."
end
end

عرض الملف

@@ -1,4 +1,4 @@
require 'resolv'
require "resolv"
class Domain
@@ -7,11 +7,12 @@ class Domain
end
def verify_with_dns
return false unless self.verification_method == 'DNS'
result = resolver.getresources(self.name, Resolv::DNS::Resource::IN::TXT)
if result.map { |d| d.data.to_s.strip}.include?(self.dns_verification_string)
return false unless verification_method == "DNS"
result = resolver.getresources(name, Resolv::DNS::Resource::IN::TXT)
if result.map { |d| d.data.to_s.strip }.include?(dns_verification_string)
self.verified_at = Time.now
self.save
save
else
false
end

عرض الملف

@@ -26,19 +26,19 @@ class HTTPEndpoint < ApplicationRecord
include HasUUID
belongs_to :server
has_many :routes, :as => :endpoint
has_many :additional_route_endpoints, :dependent => :destroy, :as => :endpoint
has_many :routes, as: :endpoint
has_many :additional_route_endpoints, dependent: :destroy, as: :endpoint
ENCODINGS = ['BodyAsJSON', 'FormData']
FORMATS = ['Hash', 'RawMessage']
ENCODINGS = ["BodyAsJSON", "FormData"]
FORMATS = ["Hash", "RawMessage"]
before_destroy :update_routes
validates :name, :presence => true
validates :url, :presence => true
validates :encoding, :inclusion => {:in => ENCODINGS}
validates :format, :inclusion => {:in => FORMATS}
validates :timeout, :numericality => {:greater_than_or_equal_to => 5, :less_than_or_equal_to => 60}
validates :name, presence: true
validates :url, presence: true
validates :encoding, inclusion: { in: ENCODINGS }
validates :format, inclusion: { in: FORMATS }
validates :timeout, numericality: { greater_than_or_equal_to: 5, less_than_or_equal_to: 60 }
default_value :timeout, -> { DEFAULT_TIMEOUT }
@@ -51,7 +51,7 @@ class HTTPEndpoint < ApplicationRecord
end
def update_routes
self.routes.each { |r| r.update(:endpoint => nil, :mode => 'Reject') }
routes.each { |r| r.update(endpoint: nil, mode: "Reject") }
end
end

عرض الملف

@@ -18,27 +18,23 @@ class IncomingMessagePrototype
end
def from_address
@from.gsub(/.*</, '').gsub(/>.*/, '').strip
@from.gsub(/.*</, "").gsub(/>.*/, "").strip
end
def route
@routes ||= begin
if @to.present?
uname, domain = @to.split('@', 2)
uname, tag = uname.split('+', 2)
@server.routes.includes(:domain).where(:domains => {:name => domain}, :name => uname).first
else
nil
end
@routes ||= if @to.present?
uname, domain = @to.split("@", 2)
uname, tag = uname.split("+", 2)
@server.routes.includes(:domain).where(domains: { name: domain }, name: uname).first
end
end
def attachments
(@attachments || []).map do |attachment|
{
:name => attachment[:name],
:content_type => attachment[:content_type] || 'application/octet-stream',
:data => attachment[:base64] ? Base64.decode64(attachment[:data]) : attachment[:data]
name: attachment[:name],
content_type: attachment[:content_type] || "application/octet-stream",
data: attachment[:base64] ? Base64.decode64(attachment[:data]) : attachment[:data]
}
end
end
@@ -47,10 +43,10 @@ class IncomingMessagePrototype
if valid?
messages = route.create_messages do |message|
message.rcpt_to = @to
message.mail_from = self.from_address
message.raw_message = self.raw_message
message.mail_from = from_address
message.raw_message = raw_message
end
{route.description => {:id => messages.first.id, :token => messages.first.token}}
{ route.description => { id: messages.first.id, token: messages.first.token } }
else
false
end
@@ -66,7 +62,7 @@ class IncomingMessagePrototype
end
def validate
@errors = Array.new
@errors = []
if route.nil?
@errors << "NoRoutesFound"
end
@@ -91,11 +87,11 @@ class IncomingMessagePrototype
mail.message_id = "<#{SecureRandom.uuid}@#{Postal.config.dns.return_path}>"
attachments.each do |attachment|
mail.attachments[attachment[:name]] = {
:mime_type => attachment[:content_type],
:content => attachment[:data]
mime_type: attachment[:content_type],
content: attachment[:data]
}
end
mail.header['Received'] = "from #{@source_type} (#{@ip} [#{@ip}]) by Postal with HTTP; #{Time.now.utc.rfc2822.to_s}"
mail.header["Received"] = "from #{@source_type} (#{@ip} [#{@ip}]) by Postal with HTTP; #{Time.now.utc.rfc2822}"
mail.to_s
end
end

عرض الملف

@@ -16,9 +16,9 @@ class IPAddress < ApplicationRecord
belongs_to :ip_pool
validates :ipv4, :presence => true, :uniqueness => true
validates :hostname, :presence => true
validates :ipv6, :uniqueness => {:allow_blank => true}
validates :ipv4, presence: true, uniqueness: true
validates :hostname, presence: true
validates :ipv6, uniqueness: { allow_blank: true }
validates :priority, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 100, only_integer: true }
scope :order_by_priority, -> { order(priority: :desc) }

عرض الملف

@@ -18,16 +18,16 @@ class IPPool < ApplicationRecord
include HasUUID
validates :name, :presence => true
validates :name, presence: true
has_many :ip_addresses, :dependent => :restrict_with_exception
has_many :servers, :dependent => :restrict_with_exception
has_many :organization_ip_pools, :dependent => :destroy
has_many :organizations, :through => :organization_ip_pools
has_many :ip_pool_rules, :dependent => :destroy
has_many :ip_addresses, dependent: :restrict_with_exception
has_many :servers, dependent: :restrict_with_exception
has_many :organization_ip_pools, dependent: :destroy
has_many :organizations, through: :organization_ip_pools
has_many :ip_pool_rules, dependent: :destroy
def self.default
where(:default => true).order(:id).first
where(default: true).order(:id).first
end
end

عرض الملف

@@ -17,24 +17,24 @@ class IPPoolRule < ApplicationRecord
include HasUUID
belongs_to :owner, :polymorphic => true
belongs_to :owner, polymorphic: true
belongs_to :ip_pool
validate :validate_from_and_to_addresses
validate :validate_ip_pool_belongs_to_organization
def from
from_text ? from_text.gsub(/\r/, '').split(/\n/).map(&:strip) : []
from_text ? from_text.gsub(/\r/, "").split(/\n/).map(&:strip) : []
end
def to
to_text ? to_text.gsub(/\r/, '').split(/\n/).map(&:strip) : []
to_text ? to_text.gsub(/\r/, "").split(/\n/).map(&:strip) : []
end
def apply_to_message?(message)
if from.present? && message.headers['from'].present?
if from.present? && message.headers["from"].present?
from.each do |condition|
if message.headers['from'].any? { |f| self.class.address_matches?(condition, f) }
if message.headers["from"].any? { |f| self.class.address_matches?(condition, f) }
return true
end
end
@@ -54,28 +54,29 @@ class IPPoolRule < ApplicationRecord
private
def validate_from_and_to_addresses
if self.from.empty? && self.to.empty?
return unless from.empty? && to.empty?
errors.add :base, "At least one rule condition must be specified"
end
end
def validate_ip_pool_belongs_to_organization
org = self.owner.is_a?(Organization) ? self.owner : self.owner.organization
if self.ip_pool && self.ip_pool_id_changed? && !org.ip_pools.include?(self.ip_pool)
org = owner.is_a?(Organization) ? owner : owner.organization
return unless ip_pool && ip_pool_id_changed? && !org.ip_pools.include?(ip_pool)
errors.add :ip_pool_id, "must belong to the organization"
end
end
def self.address_matches?(condition, address)
address = Postal::Helpers.strip_name_from_address(address)
if condition =~ /@/
parts = address.split('@')
domain, uname = parts.pop, parts.join('@')
uname, _ = uname.split('+', 2)
parts = address.split("@")
domain = parts.pop
uname = parts.join("@")
uname, = uname.split("+", 2)
condition == "#{uname}@#{domain}"
else
# Match as a domain
condition == address.split('@').last
condition == address.split("@").last
end
end

عرض الملف

@@ -23,41 +23,41 @@
class Organization < ApplicationRecord
RESERVED_PERMALINKS = ['new', 'edit', 'remove', 'delete', 'destroy', 'admin', 'mail', 'org', 'server']
RESERVED_PERMALINKS = ["new", "edit", "remove", "delete", "destroy", "admin", "mail", "org", "server"]
INITIAL_QUOTA = 10
INITIAL_SUPER_QUOTA = 10000
INITIAL_SUPER_QUOTA = 10_000
include HasUUID
include HasSoftDestroy
validates :name, :presence => true
validates :permalink, :presence => true, :format => {:with => /\A[a-z0-9\-]*\z/}, :uniqueness => true, :exclusion => {:in => RESERVED_PERMALINKS}
validates :time_zone, :presence => true
validates :name, presence: true
validates :permalink, presence: true, format: { with: /\A[a-z0-9-]*\z/ }, uniqueness: true, exclusion: { in: RESERVED_PERMALINKS }
validates :time_zone, presence: true
default_value :time_zone, -> { 'UTC' }
default_value :permalink, -> { Organization.find_unique_permalink(self.name) if self.name }
default_value :time_zone, -> { "UTC" }
default_value :permalink, -> { Organization.find_unique_permalink(name) if name }
belongs_to :owner, :class_name => 'User'
has_many :organization_users, :dependent => :destroy
has_many :users, :through => :organization_users, :source_type => 'User'
has_many :user_invites, :through => :organization_users, :source_type => 'UserInvite', :source => :user
has_many :servers, :dependent => :destroy
has_many :domains, :as => :owner, :dependent => :destroy
has_many :organization_ip_pools, :dependent => :destroy
has_many :ip_pools, :through => :organization_ip_pools
has_many :ip_pool_rules, :dependent => :destroy, :as => :owner
belongs_to :owner, class_name: "User"
has_many :organization_users, dependent: :destroy
has_many :users, through: :organization_users, source_type: "User"
has_many :user_invites, through: :organization_users, source_type: "UserInvite", source: :user
has_many :servers, dependent: :destroy
has_many :domains, as: :owner, dependent: :destroy
has_many :organization_ip_pools, dependent: :destroy
has_many :ip_pools, through: :organization_ip_pools
has_many :ip_pool_rules, dependent: :destroy, as: :owner
after_create do
if pool = IPPool.default
self.ip_pools << IPPool.default
ip_pools << IPPool.default
end
end
def status
if self.suspended?
'Suspended'
if suspended?
"Suspended"
else
'Active'
"Active"
end
end
@@ -71,25 +71,25 @@ class Organization < ApplicationRecord
def user_assignment(user)
@user_assignments ||= {}
@user_assignments[user.id] ||= organization_users.where(:user => user).first
@user_assignments[user.id] ||= organization_users.where(user: user).first
end
def make_owner(new_owner)
user_assignment(new_owner).update(:admin => true, :all_servers => true)
update(:owner => new_owner)
user_assignment(new_owner).update(admin: true, all_servers: true)
update(owner: new_owner)
end
# This is an array of addresses that should receive notifications for this organization
def notification_addresses
self.users.map(&:email_tag)
users.map(&:email_tag)
end
def self.find_unique_permalink(name)
loop.each_with_index do |_, i|
i = i + 1
i += 1
proposal = name.parameterize
proposal += "-#{i}" if i > 1
unless self.where(:permalink => proposal).exists?
unless where(permalink: proposal).exists?
return proposal
end
end
@@ -97,9 +97,9 @@ class Organization < ApplicationRecord
def self.[](id)
if id.is_a?(String)
where(:permalink => id).first
where(permalink: id).first
else
where(:id => id.to_i).first
where(id: id.to_i).first
end
end

عرض الملف

@@ -10,6 +10,8 @@
#
class OrganizationIPPool < ApplicationRecord
belongs_to :organization
belongs_to :ip_pool
end

عرض الملف

@@ -14,6 +14,6 @@
class OrganizationUser < ApplicationRecord
belongs_to :organization
belongs_to :user, :polymorphic => true, :optional => true
belongs_to :user, polymorphic: true, optional: true
end

عرض الملف

@@ -1,4 +1,4 @@
require 'resolv'
require "resolv"
class OutgoingMessagePrototype
@@ -29,9 +29,7 @@ class OutgoingMessagePrototype
end
end
def message_id
@message_id
end
attr_reader :message_id
def from_address
Postal::Helpers.strip_name_from_address(@from)
@@ -59,15 +57,15 @@ class OutgoingMessagePrototype
end
def to_addresses
@to.is_a?(String) ? @to.to_s.split(/\,\s*/) : @to.to_a
@to.is_a?(String) ? @to.to_s.split(/,\s*/) : @to.to_a
end
def cc_addresses
@cc.is_a?(String) ? @cc.to_s.split(/\,\s*/) : @cc.to_a
@cc.is_a?(String) ? @cc.to_s.split(/,\s*/) : @cc.to_a
end
def bcc_addresses
@bcc.is_a?(String) ? @bcc.to_s.split(/\,\s*/) : @bcc.to_a
@bcc.is_a?(String) ? @bcc.to_s.split(/,\s*/) : @bcc.to_a
end
def all_addresses
@@ -98,30 +96,30 @@ class OutgoingMessagePrototype
def attachments
(@attachments || []).map do |attachment|
{
:name => attachment[:name],
:content_type => attachment[:content_type] || 'application/octet-stream',
:data => attachment[:base64] ? Base64.decode64(attachment[:data]) : attachment[:data]
name: attachment[:name],
content_type: attachment[:content_type] || "application/octet-stream",
data: attachment[:base64] ? Base64.decode64(attachment[:data]) : attachment[:data]
}
end
end
def validate
@errors = Array.new
@errors = []
if to_addresses.empty? && cc_addresses.empty? && bcc_addresses.empty?
@errors << "NoRecipients"
end
if to_addresses.size > 50
@errors << 'TooManyToAddresses'
@errors << "TooManyToAddresses"
end
if cc_addresses.size > 50
@errors << 'TooManyCCAddresses'
@errors << "TooManyCCAddresses"
end
if bcc_addresses.size > 50
@errors << 'TooManyBCCAddresses'
@errors << "TooManyBCCAddresses"
end
if @plain_body.blank? && @html_body.blank?
@@ -136,7 +134,7 @@ class OutgoingMessagePrototype
@errors << "UnauthenticatedFromAddress"
end
if attachments && !attachments.empty?
if attachments.present?
attachments.each_with_index do |attachment, index|
if attachment[:name].blank?
@errors << "AttachmentMissingName" unless @errors.include?("AttachmentMissingName")
@@ -154,18 +152,18 @@ class OutgoingMessagePrototype
if @custom_headers.is_a?(Hash)
@custom_headers.each { |key, value| mail[key.to_s] = value.to_s }
end
mail.to = self.to_addresses.join(', ') if self.to_addresses.present?
mail.cc = self.cc_addresses.join(', ') if self.cc_addresses.present?
mail.to = to_addresses.join(", ") if to_addresses.present?
mail.cc = cc_addresses.join(", ") if cc_addresses.present?
mail.from = @from
mail.sender = @sender
mail.subject = @subject
mail.reply_to = @reply_to
mail.part :content_type => "multipart/alternative" do |p|
if !@plain_body.blank?
mail.part content_type: "multipart/alternative" do |p|
if @plain_body.present?
p.text_part = Mail::Part.new
p.text_part.body = @plain_body
end
if !@html_body.blank?
if @html_body.present?
p.html_part = Mail::Part.new
p.html_part.content_type = "text/html; charset=UTF-8"
p.html_part.body = @html_body
@@ -173,11 +171,11 @@ class OutgoingMessagePrototype
end
attachments.each do |attachment|
mail.attachments[attachment[:name]] = {
:mime_type => attachment[:content_type],
:content => attachment[:data]
mime_type: attachment[:content_type],
content: attachment[:data]
}
end
mail.header['Received'] = "from #{@source_type} (#{self.resolved_hostname} [#{@ip}]) by Postal with HTTP; #{Time.now.utc.rfc2822.to_s}"
mail.header["Received"] = "from #{@source_type} (#{resolved_hostname} [#{@ip}]) by Postal with HTTP; #{Time.now.utc.rfc2822}"
mail.message_id = "<#{@message_id}>"
mail.to_s
end
@@ -185,21 +183,25 @@ class OutgoingMessagePrototype
def create_message(address)
message = @server.message_db.new_message
message.scope = 'outgoing'
message.scope = "outgoing"
message.rcpt_to = address
message.mail_from = self.from_address
message.domain_id = self.domain.id
message.raw_message = self.raw_message
message.tag = self.tag
message.credential_id = self.credential&.id
message.mail_from = from_address
message.domain_id = domain.id
message.raw_message = raw_message
message.tag = tag
message.credential_id = credential&.id
message.received_with_ssl = true
message.bounce = @bounce ? 1 : 0
message.save
{:id => message.id, :token => message.token}
{ id: message.id, token: message.token }
end
def resolved_hostname
@resolved_hostname ||= Resolv.new.getname(@ip) rescue @ip
@resolved_hostname ||= begin
Resolv.new.getname(@ip)
rescue StandardError
@ip
end
end
end

عرض الملف

@@ -29,21 +29,21 @@ class QueuedMessage < ApplicationRecord
include HasMessage
belongs_to :server
belongs_to :ip_address, :optional => true
belongs_to :user, :optional => true
belongs_to :ip_address, optional: true
belongs_to :user, optional: true
before_create :allocate_ip_address
after_commit :queue, :on => :create
after_commit :queue, on: :create
scope :unlocked, -> { where(:locked_at => nil) }
scope :unlocked, -> { where(locked_at: nil) }
scope :retriable, -> { where("retry_after IS NULL OR retry_after <= ?", 30.seconds.from_now) }
def retriable?
self.retry_after.nil? || self.retry_after <= 30.seconds.from_now
retry_after.nil? || retry_after <= 30.seconds.from_now
end
def queue
UnqueueMessageJob.queue(queue_name, :id => self.id)
UnqueueMessageJob.queue(queue_name, id: id)
end
def queue!
@@ -56,21 +56,21 @@ class QueuedMessage < ApplicationRecord
end
def send_bounce
if self.message.send_bounces?
Postal::BounceMessage.new(self.server, self.message).queue
end
return unless message.send_bounces?
Postal::BounceMessage.new(server, message).queue
end
def allocate_ip_address
if Postal.ip_pools? && self.message && pool = self.server.ip_pool_for_message(self.message)
return unless Postal.ip_pools? && message && pool = server.ip_pool_for_message(message)
self.ip_address = pool.ip_addresses.select_by_priority
end
end
def acquire_lock
time = Time.now
locker = Postal.locker_name
rows = self.class.where(:id => self.id, :locked_by => nil, :locked_at => nil).update_all(:locked_by => locker, :locked_at => time)
rows = self.class.where(id: id, locked_by: nil, locked_at: nil).update_all(locked_by: locker, locked_at: time)
if rows == 1
self.locked_by = locker
self.locked_at = time
@@ -81,20 +81,20 @@ class QueuedMessage < ApplicationRecord
end
def retry_later(time = nil)
retry_time = time || self.class.calculate_retry_time(self.attempts, 5.minutes)
retry_time = time || self.class.calculate_retry_time(attempts, 5.minutes)
self.locked_by = nil
self.locked_at = nil
update_columns(:locked_by => nil, :locked_at => nil, :retry_after => Time.now + retry_time, :attempts => self.attempts + 1)
update_columns(locked_by: nil, locked_at: nil, retry_after: Time.now + retry_time, attempts: attempts + 1)
end
def unlock
self.locked_by = nil
self.locked_at = nil
update_columns(:locked_by => nil, :locked_at => nil)
update_columns(locked_by: nil, locked_at: nil)
end
def self.calculate_retry_time(attempts, initial_period)
(1.3 ** attempts) * initial_period
(1.3**attempts) * initial_period
end
def locked?
@@ -105,13 +105,14 @@ class QueuedMessage < ApplicationRecord
unless locked?
raise Postal::Error, "Must lock current message before locking any friends"
end
if self.batch_key.nil?
if batch_key.nil?
[]
else
time = Time.now
locker = Postal.locker_name
self.class.retriable.where(:batch_key => self.batch_key, :ip_address_id => self.ip_address_id, :locked_by => nil, :locked_at => nil).limit(limit).update_all(:locked_by => locker, :locked_at => time)
QueuedMessage.where(:batch_key => self.batch_key, :ip_address_id => self.ip_address_id, :locked_by => locker, :locked_at => time).where.not(id: self.id)
self.class.retriable.where(batch_key: batch_key, ip_address_id: ip_address_id, locked_by: nil, locked_at: nil).limit(limit).update_all(locked_by: locker, locked_at: time)
QueuedMessage.where(batch_key: batch_key, ip_address_id: ip_address_id, locked_by: locker, locked_at: time).where.not(id: id)
end
end

عرض الملف

@@ -22,22 +22,22 @@
class Route < ApplicationRecord
MODES = ['Endpoint', 'Accept', 'Hold', 'Bounce', 'Reject']
MODES = ["Endpoint", "Accept", "Hold", "Bounce", "Reject"]
include HasUUID
belongs_to :server
belongs_to :domain, :optional => true
belongs_to :endpoint, :polymorphic => true, :optional => true
has_many :additional_route_endpoints, :dependent => :destroy
belongs_to :domain, optional: true
belongs_to :endpoint, polymorphic: true, optional: true
has_many :additional_route_endpoints, dependent: :destroy
SPAM_MODES = ['Mark', 'Quarantine', 'Fail']
ENDPOINT_TYPES = ['SMTPEndpoint', 'HTTPEndpoint', 'AddressEndpoint']
SPAM_MODES = ["Mark", "Quarantine", "Fail"]
ENDPOINT_TYPES = ["SMTPEndpoint", "HTTPEndpoint", "AddressEndpoint"]
validates :name, :presence => true, :format => /\A(([a-z0-9\-\.]*)|(\*)|(__returnpath__))\z/
validates :spam_mode, :inclusion => {:in => SPAM_MODES}
validates :endpoint, :presence => {:if => proc { self.mode == 'Endpoint' }}
validates :domain_id, :presence => {:unless => :return_path?}
validates :name, presence: true, format: /\A(([a-z0-9\-.]*)|(\*)|(__returnpath__))\z/
validates :spam_mode, inclusion: { in: SPAM_MODES }
validates :endpoint, presence: { if: proc { mode == "Endpoint" } }
validates :domain_id, presence: { unless: :return_path? }
validate :validate_route_is_routed
validate :validate_domain_belongs_to_server
validate :validate_endpoint_belongs_to_server
@@ -47,7 +47,7 @@ class Route < ApplicationRecord
after_save :save_additional_route_endpoints
random_string :token, :type => :chars, :length => 8, :unique => true
random_string :token, type: :chars, length: 8, unique: true
def return_path?
name == "__returnpath__"
@@ -62,12 +62,10 @@ class Route < ApplicationRecord
end
def _endpoint
@endpoint ||= begin
if self.mode == 'Endpoint'
endpoint ? "#{endpoint.class}##{endpoint.uuid}" : nil
if mode == "Endpoint"
@endpoint ||= endpoint ? "#{endpoint.class}##{endpoint.uuid}" : nil
else
self.mode
end
@endpoint ||= mode
end
end
@@ -75,27 +73,26 @@ class Route < ApplicationRecord
if value.blank?
self.endpoint = nil
self.mode = nil
else
if value =~ /\#/
class_name, id = value.split('#', 2)
elsif value =~ /\#/
class_name, id = value.split("#", 2)
unless ENDPOINT_TYPES.include?(class_name)
raise Postal::Error, "Invalid endpoint class name '#{class_name}'"
end
self.endpoint = class_name.constantize.find_by_uuid(id)
self.mode = 'Endpoint'
self.mode = "Endpoint"
else
self.endpoint = nil
self.mode = value
end
end
end
def forward_address
@forward_address ||= "#{token}@#{Postal.config.dns.route_domain}"
end
def wildcard?
self.name == '*'
name == "*"
end
def additional_route_endpoints_array
@@ -107,13 +104,14 @@ class Route < ApplicationRecord
end
def save_additional_route_endpoints
if @additional_route_endpoints_array
return unless @additional_route_endpoints_array
seen = []
@additional_route_endpoints_array.each do |item|
if existing = additional_route_endpoints.find_by_endpoint(item)
seen << existing.id
else
route = additional_route_endpoints.build(:_endpoint => item)
route = additional_route_endpoints.build(_endpoint: item)
if route.save
seen << route.id
else
@@ -124,33 +122,33 @@ class Route < ApplicationRecord
end
end
end
additional_route_endpoints.where.not(:id => seen).destroy_all
end
additional_route_endpoints.where.not(id: seen).destroy_all
end
#
# This message will create a suitable number of message objects for messages that
# are destined for this route. It receives a block which can set the message content
#  are destined for this route. It receives a block which can set the message content
# but most information is specified already.
#
# Returns an array of created messages.
#
def create_messages(&block)
messages = []
message = self.build_message
if self.mode == 'Endpoint' && self.server.message_db.schema_version >= 18
message.endpoint_type = self.endpoint_type
message.endpoint_id = self.endpoint_id
message = build_message
if mode == "Endpoint" && server.message_db.schema_version >= 18
message.endpoint_type = endpoint_type
message.endpoint_id = endpoint_id
end
block.call(message)
message.save
messages << message
# Also create any messages for additional endpoints that might exist
if self.mode == 'Endpoint' && self.server.message_db.schema_version >= 18
self.additional_route_endpoints.each do |endpoint|
if mode == "Endpoint" && server.message_db.schema_version >= 18
additional_route_endpoints.each do |endpoint|
next unless endpoint.endpoint
message = self.build_message
message = build_message
message.endpoint_id = endpoint.endpoint_id
message.endpoint_type = endpoint.endpoint_type
block.call(message)
@@ -163,69 +161,67 @@ class Route < ApplicationRecord
end
def build_message
message = self.server.message_db.new_message
message.scope = 'incoming'
message.rcpt_to = self.description
message.domain_id = self.domain&.id
message.route_id = self.id
message = server.message_db.new_message
message.scope = "incoming"
message.rcpt_to = description
message.domain_id = domain&.id
message.route_id = id
message
end
private
def validate_route_is_routed
if self.mode.nil?
return unless mode.nil?
errors.add :endpoint, "must be chosen"
end
end
def validate_domain_belongs_to_server
if self.domain && ![self.server, self.server.organization].include?(self.domain.owner)
if domain && ![server, server.organization].include?(domain.owner)
errors.add :domain, :invalid
end
if self.domain && !self.domain.verified?
return unless domain && !domain.verified?
errors.add :domain, "has not been verified yet"
end
end
def validate_endpoint_belongs_to_server
if self.endpoint && self.endpoint&.server != self.server
return unless endpoint && endpoint&.server != server
errors.add :endpoint, :invalid
end
end
def validate_name_uniqueness
return if self.server.nil?
if self.domain
if route = Route.includes(:domain).where(:domains => {:name => self.domain.name}, :name => self.name).where.not(:id => self.id).first
return if server.nil?
if domain
if route = Route.includes(:domain).where(domains: { name: domain.name }, name: name).where.not(id: id).first
errors.add :name, "is configured on the #{route.server.full_permalink} mail server"
end
else
if route = Route.where(:name => "__returnpath__").where.not(:id => self.id).exists?
elsif route = Route.where(name: "__returnpath__").where.not(id: id).exists?
errors.add :base, "A return path route already exists for this server"
end
end
end
def validate_return_path_route_endpoints
if return_path?
if self.mode != 'Endpoint' || self.endpoint_type != 'HTTPEndpoint'
return unless return_path?
return unless mode != "Endpoint" || endpoint_type != "HTTPEndpoint"
errors.add :base, "Return path routes must point to an HTTP endpoint"
end
end
end
def validate_no_additional_routes_on_non_endpoint_route
if self.mode != 'Endpoint' && !self.additional_route_endpoints_array.empty?
return unless mode != "Endpoint" && !additional_route_endpoints_array.empty?
errors.add :base, "Additional routes are not permitted unless the primary route is an actual endpoint"
end
end
def self.find_by_name_and_domain(name, domain)
route = Route.includes(:domain).where(:name => name, :domains => {:name => domain}).first
route = Route.includes(:domain).where(name: name, domains: { name: domain }).first
if route.nil?
route = Route.includes(:domain).where(:name => '*', :domains => {:name => domain}).first
route = Route.includes(:domain).where(name: "*", domains: { name: domain }).first
end
route
end

عرض الملف

@@ -41,7 +41,7 @@
class Server < ApplicationRecord
RESERVED_PERMALINKS = ['new', 'all', 'search', 'stats', 'edit', 'manage', 'delete', 'destroy', 'remove']
RESERVED_PERMALINKS = ["new", "all", "search", "stats", "edit", "manage", "delete", "destroy", "remove"]
include HasUUID
include HasSoftDestroy
@@ -49,55 +49,55 @@ class Server < ApplicationRecord
attr_accessor :provision_database
belongs_to :organization
belongs_to :ip_pool, :optional => true
has_many :domains, :dependent => :destroy, :as => :owner
has_many :credentials, :dependent => :destroy
has_many :smtp_endpoints, :dependent => :destroy
has_many :http_endpoints, :dependent => :destroy
has_many :address_endpoints, :dependent => :destroy
has_many :routes, :dependent => :destroy
has_many :queued_messages, :dependent => :delete_all
has_many :webhooks, :dependent => :destroy
has_many :webhook_requests, :dependent => :destroy
has_many :track_domains, :dependent => :destroy
has_many :ip_pool_rules, :dependent => :destroy, :as => :owner
belongs_to :ip_pool, optional: true
has_many :domains, dependent: :destroy, as: :owner
has_many :credentials, dependent: :destroy
has_many :smtp_endpoints, dependent: :destroy
has_many :http_endpoints, dependent: :destroy
has_many :address_endpoints, dependent: :destroy
has_many :routes, dependent: :destroy
has_many :queued_messages, dependent: :delete_all
has_many :webhooks, dependent: :destroy
has_many :webhook_requests, dependent: :destroy
has_many :track_domains, dependent: :destroy
has_many :ip_pool_rules, dependent: :destroy, as: :owner
MODES = ['Live', 'Development']
MODES = ["Live", "Development"]
random_string :token, :type => :chars, :length => 6, :unique => true, :upper_letters_only => true
default_value :permalink, -> { name ? name.parameterize : nil}
random_string :token, type: :chars, length: 6, unique: true, upper_letters_only: true
default_value :permalink, -> { name ? name.parameterize : nil }
default_value :raw_message_retention_days, -> { 30 }
default_value :raw_message_retention_size, -> { 2048 }
default_value :message_retention_days, -> { 60 }
default_value :spam_threshold, -> { Postal.config.general.default_spam_threshold }
default_value :spam_failure_threshold, -> { Postal.config.general.default_spam_failure_threshold }
validates :name, :presence => true, :uniqueness => {:scope => :organization_id}
validates :mode, :inclusion => {:in => MODES}
validates :permalink, :presence => true, :uniqueness => {:scope => :organization_id}, :format => {:with => /\A[a-z0-9\-]*\z/}, :exclusion => {:in => RESERVED_PERMALINKS}
validates :name, presence: true, uniqueness: { scope: :organization_id }
validates :mode, inclusion: { in: MODES }
validates :permalink, presence: true, uniqueness: { scope: :organization_id }, format: { with: /\A[a-z0-9-]*\z/ }, exclusion: { in: RESERVED_PERMALINKS }
validate :validate_ip_pool_belongs_to_organization
before_validation(:on => :create) do
self.token = self.token.downcase if self.token
before_validation(on: :create) do
self.token = token.downcase if token
end
after_create do
unless self.provision_database == false
unless provision_database == false
message_db.provisioner.provision
end
end
after_commit(:on => :destroy) do
unless self.provision_database == false
after_commit(on: :destroy) do
unless provision_database == false
message_db.provisioner.drop
end
end
def status
if self.suspended?
'Suspended'
if suspended?
"Suspended"
else
self.mode
mode
end
end
@@ -110,12 +110,12 @@ class Server < ApplicationRecord
end
def actual_suspension_reason
if suspended?
return unless suspended?
if suspended_at.nil?
organization.suspension_reason
else
self.suspension_reason
end
suspension_reason
end
end
@@ -124,30 +124,28 @@ class Server < ApplicationRecord
end
def message_db
@message_db ||= Postal::MessageDB::Database.new(self.organization_id, self.id)
@message_db ||= Postal::MessageDB::Database.new(organization_id, id)
end
def message(id)
message_db.message(id)
end
delegate :message, to: :message_db
def message_rate
@message_rate ||= message_db.live_stats.total(60, :types => [:incoming, :outgoing]) / 60.0
@message_rate ||= message_db.live_stats.total(60, types: [:incoming, :outgoing]) / 60.0
end
def held_messages
@held_messages ||= message_db.messages(:where => {:held => 1}, :count => true)
@held_messages ||= message_db.messages(where: { held: 1 }, count: true)
end
def throughput_stats
@throughput_stats ||= begin
incoming = message_db.live_stats.total(60, :types => [:incoming])
outgoing = message_db.live_stats.total(60, :types => [:outgoing])
incoming = message_db.live_stats.total(60, types: [:incoming])
outgoing = message_db.live_stats.total(60, types: [:outgoing])
outgoing_usage = send_limit ? (outgoing / send_limit.to_f) * 100 : 0
{
:incoming => incoming,
:outgoing => outgoing,
:outgoing_usage => outgoing_usage
incoming: incoming,
outgoing: outgoing,
outgoing_usage: outgoing_usage
}
end
end
@@ -166,8 +164,10 @@ class Server < ApplicationRecord
end
def domain_stats
domains = Domain.where(:owner_id => self.id, :owner_type => 'Server').to_a
total, unverified, bad_dns = 0, 0, 0
domains = Domain.where(owner_id: id, owner_type: "Server").to_a
total = 0
unverified = 0
bad_dns = 0
domains.each do |domain|
total += 1
unverified += 1 unless domain.verified?
@@ -178,29 +178,29 @@ class Server < ApplicationRecord
def webhook_hash
{
:uuid => self.uuid,
:name => self.name,
:permalink => self.permalink,
:organization => self.organization&.permalink
uuid: uuid,
name: name,
permalink: permalink,
organization: organization&.permalink
}
end
def send_volume
@send_volume ||= message_db.live_stats.total(60, :types => [:outgoing])
@send_volume ||= message_db.live_stats.total(60, types: [:outgoing])
end
def send_limit_approaching?
self.send_limit && (send_volume >= self.send_limit * 0.90)
send_limit && (send_volume >= send_limit * 0.90)
end
def send_limit_exceeded?
self.send_limit && send_volume >= self.send_limit
send_limit && send_volume >= send_limit
end
def send_limit_warning(type)
AppMailer.send("server_send_limit_#{type}", self).deliver
self.update_column("send_limit_#{type}_notified_at", Time.now)
WebhookRequest.trigger(self, "SendLimit#{type.to_s.capitalize}", :server => webhook_hash, :volume => self.send_volume, :limit => self.send_limit)
update_column("send_limit_#{type}_notified_at", Time.now)
WebhookRequest.trigger(self, "SendLimit#{type.to_s.capitalize}", server: webhook_hash, volume: send_volume, limit: send_limit)
end
def queue_size
@@ -209,36 +209,38 @@ class Server < ApplicationRecord
def stats
{
:queue => queue_size,
:held => self.held_messages,
:bounce_rate => self.bounce_rate,
:message_rate => self.message_rate,
:throughput => self.throughput_stats,
:size => self.message_db.total_size
queue: queue_size,
held: held_messages,
bounce_rate: bounce_rate,
message_rate: message_rate,
throughput: throughput_stats,
size: message_db.total_size
}
end
def authenticated_domain_for_address(address)
return nil if address.blank?
address = Postal::Helpers.strip_name_from_address(address)
uname, domain_name = address.split('@', 2)
uname, domain_name = address.split("@", 2)
return nil unless uname
return nil unless domain_name
uname, _ = uname.split('+', 2)
uname, = uname.split("+", 2)
# Check the server's domain
if domain = Domain.verified.order(:owner_type => :desc).where("(owner_type = 'Organization' AND owner_id = ?) OR (owner_type = 'Server' AND owner_id = ?)", self.organization_id, self.id).where(:name => domain_name).first
if domain = Domain.verified.order(owner_type: :desc).where("(owner_type = 'Organization' AND owner_id = ?) OR (owner_type = 'Server' AND owner_id = ?)", organization_id, id).where(name: domain_name).first
return domain
end
if any_domain = self.domains.verified.where(:use_for_any => true).order(:name).first
return any_domain
end
return unless any_domain = domains.verified.where(use_for_any: true).order(:name).first
any_domain
end
def find_authenticated_domain_from_headers(headers)
header_to_check = ['from']
header_to_check << 'sender' if self.allow_sender?
header_to_check = ["from"]
header_to_check << "sender" if allow_sender?
header_to_check.each do |header_name|
if headers[header_name].is_a?(Array)
values = headers[header_name]
@@ -257,36 +259,34 @@ class Server < ApplicationRecord
def suspend(reason)
self.suspended_at = Time.now
self.suspension_reason = reason
self.save!
save!
AppMailer.server_suspended(self).deliver
end
def unsuspend
self.suspended_at = nil
self.suspension_reason = nil
self.save!
save!
end
def validate_ip_pool_belongs_to_organization
if self.ip_pool && self.ip_pool_id_changed? && !self.organization.ip_pools.include?(self.ip_pool)
return unless ip_pool && ip_pool_id_changed? && !organization.ip_pools.include?(ip_pool)
errors.add :ip_pool_id, "must belong to the organization"
end
end
def ip_pool_for_message(message)
if message.scope == 'outgoing'
[self, self.organization].each do |scope|
rules = scope.ip_pool_rules.order(:created_at => :desc)
return unless message.scope == "outgoing"
[self, organization].each do |scope|
rules = scope.ip_pool_rules.order(created_at: :desc)
rules.each do |rule|
if rule.apply_to_message?(message)
return rule.ip_pool
end
end
end
self.ip_pool
else
nil
end
ip_pool
end
def self.triggered_send_limit(type)
@@ -297,29 +297,29 @@ class Server < ApplicationRecord
def self.send_send_limit_notifications
[:approaching, :exceeded].each_with_object({}) do |type, hash|
hash[type] = 0
servers = self.triggered_send_limit(type)
unless servers.empty?
servers = triggered_send_limit(type)
next if servers.empty?
servers.each do |server|
hash[type] += 1
server.send_limit_warning(type)
end
end
end
end
def self.[](id, extra = nil)
server = nil
if id.is_a?(String)
if id =~ /\A(\w+)\/(\w+)\z/
server = includes(:organization).where(:organizations => {:permalink => $1}, :permalink => $2).first
server = includes(:organization).where(organizations: { permalink: ::Regexp.last_match(1) }, permalink: ::Regexp.last_match(2)).first
end
else
server = where(:id => id).first
server = where(id: id).first
end
if extra
if extra.is_a?(String)
server.domains.where(:name => extra.to_s).first
server.domains.where(name: extra.to_s).first
else
server.message(extra.to_i)
end

عرض الملف

@@ -21,17 +21,17 @@ class SMTPEndpoint < ApplicationRecord
include HasUUID
belongs_to :server
has_many :routes, :as => :endpoint
has_many :additional_route_endpoints, :dependent => :destroy, :as => :endpoint
has_many :routes, as: :endpoint
has_many :additional_route_endpoints, dependent: :destroy, as: :endpoint
SSL_MODES = ['None', 'Auto', 'STARTTLS', 'TLS']
SSL_MODES = ["None", "Auto", "STARTTLS", "TLS"]
before_destroy :update_routes
validates :name, :presence => true
validates :hostname, :presence => true, :format => /\A[a-z0-9\.\-]*\z/
validates :ssl_mode, :inclusion => {:in => SSL_MODES}
validates :port, :numericality => {:only_integer => true, :allow_blank => true}
validates :name, presence: true
validates :hostname, presence: true, format: /\A[a-z0-9.-]*\z/
validates :ssl_mode, inclusion: { in: SSL_MODES }
validates :port, numericality: { only_integer: true, allow_blank: true }
def description
"#{name} (#{hostname})"
@@ -42,7 +42,7 @@ class SMTPEndpoint < ApplicationRecord
end
def update_routes
self.routes.each { |r| r.update(:endpoint => nil, :mode => 'Reject') }
routes.each { |r| r.update(endpoint: nil, mode: "Reject") }
end
end

عرض الملف

@@ -18,7 +18,7 @@
# excluded_click_domains :text(65535)
#
require 'resolv'
require "resolv"
class TrackDomain < ApplicationRecord
@@ -27,16 +27,16 @@ class TrackDomain < ApplicationRecord
belongs_to :server
belongs_to :domain
validates :name, :presence => true, :format => {:with => /\A[a-z0-9\-]+\z/}, :uniqueness => {:scope => :domain_id, :message => "is already added"}
validates :domain_id, :uniqueness => {:scope => :server_id, :message => "already has a track domain for this server"}
validates :name, presence: true, format: { with: /\A[a-z0-9-]+\z/ }, uniqueness: { scope: :domain_id, message: "is already added" }
validates :domain_id, uniqueness: { scope: :server_id, message: "already has a track domain for this server" }
validate :validate_domain_belongs_to_server
scope :ok, -> { where(:dns_status => 'OK')}
scope :ok, -> { where(dns_status: "OK") }
after_create :check_dns, :unless => :dns_status
after_create :check_dns, unless: :dns_status
before_validation do
self.server = self.domain.server if self.domain && self.server.nil?
self.server = domain.server if domain && server.nil?
end
def full_name
@@ -48,26 +48,24 @@ class TrackDomain < ApplicationRecord
end
def dns_ok?
self.dns_status == 'OK'
dns_status == "OK"
end
def check_dns
result = self.domain.resolver.getresources(self.full_name, Resolv::DNS::Resource::IN::CNAME)
result = domain.resolver.getresources(full_name, Resolv::DNS::Resource::IN::CNAME)
records = result.map { |r| r.name.to_s.downcase }
if records.empty?
self.dns_status = 'Missing'
self.dns_error = "There is no record at #{self.full_name}"
else
if records.size == 1 && records.first == Postal.config.dns.track_domain
self.dns_status = 'OK'
self.dns_status = "Missing"
self.dns_error = "There is no record at #{full_name}"
elsif records.size == 1 && records.first == Postal.config.dns.track_domain
self.dns_status = "OK"
self.dns_error = nil
else
self.dns_status = 'Invalid'
self.dns_error = "There is a CNAME record at #{self.full_name} but it points to #{records.first} which is incorrect. It should point to #{Postal.config.dns.track_domain}."
end
self.dns_status = "Invalid"
self.dns_error = "There is a CNAME record at #{full_name} but it points to #{records.first} which is incorrect. It should point to #{Postal.config.dns.track_domain}."
end
self.dns_checked_at = Time.now
self.save!
save!
dns_ok?
end
@@ -76,9 +74,9 @@ class TrackDomain < ApplicationRecord
end
def validate_domain_belongs_to_server
if self.domain && ![self.server, self.server.organization].include?(self.domain.owner)
return unless domain && ![server, server.organization].include?(domain.owner)
errors.add :domain, "does not belong to the server or the server's organization"
end
end
end

عرض الملف

@@ -27,25 +27,23 @@ class User < ApplicationRecord
include HasUUID
require_dependency 'user/authentication'
require_dependency "user/authentication"
validates :first_name, :presence => true
validates :last_name, :presence => true
validates :email_address, :presence => true, :uniqueness => true, :format => {:with => /@/, allow_blank: true}
validates :time_zone, :presence => true
validates :first_name, presence: true
validates :last_name, presence: true
validates :email_address, presence: true, uniqueness: true, format: { with: /@/, allow_blank: true }
validates :time_zone, presence: true
default_value :time_zone, -> { 'UTC' }
default_value :time_zone, -> { "UTC" }
has_many :organization_users, :dependent => :destroy, :as => :user
has_many :organizations, :through => :organization_users
has_many :organization_users, dependent: :destroy, as: :user
has_many :organizations, through: :organization_users
def organizations_scope
@organizations_scope ||= begin
if self.admin?
Organization.present
if admin?
@organizations_scope ||= Organization.present
else
self.organizations.present
end
@organizations_scope ||= organizations.present
end
end
@@ -70,7 +68,7 @@ class User < ApplicationRecord
end
def self.[](email)
where(:email_address => email).first
where(email_address: email).first
end
end

عرض الملف

@@ -2,9 +2,9 @@ class User
has_secure_password
validates :password, :length => {:minimum => 8, :allow_blank => true}
validates :password, length: { minimum: 8, allow_blank: true }
when_attribute :password_digest, :changes_to => :anything do
when_attribute :password_digest, changes_to: :anything do
before_save do
self.password_reset_token = nil
self.password_reset_token_valid_until = nil
@@ -12,9 +12,10 @@ class User
end
def self.authenticate(email_address, password)
user = where(:email_address => email_address).first
raise Postal::Errors::AuthenticationError.new('InvalidEmailAddress') if user.nil?
raise Postal::Errors::AuthenticationError.new('InvalidPassword') unless user.authenticate(password)
user = where(email_address: email_address).first
raise Postal::Errors::AuthenticationError, "InvalidEmailAddress" if user.nil?
raise Postal::Errors::AuthenticationError, "InvalidPassword" unless user.authenticate(password)
user
end
@@ -27,9 +28,9 @@ class User
end
def begin_password_reset(return_to = nil)
self.password_reset_token = Nifty::Utils::RandomString.generate(:length => 24)
self.password_reset_token = Nifty::Utils::RandomString.generate(length: 24)
self.password_reset_token_valid_until = 1.day.from_now
self.save!
save!
AppMailer.password_reset(self, return_to).deliver
end

عرض الملف

@@ -18,10 +18,10 @@ class UserInvite < ApplicationRecord
include HasUUID
validates :email_address, :presence => true, :uniqueness => true, :format => {:with => /@/, :allow_blank => true}
validates :email_address, presence: true, uniqueness: true, format: { with: /@/, allow_blank: true }
has_many :organization_users, :dependent => :destroy, :as => :user
has_many :organizations, :through => :organization_users
has_many :organization_users, dependent: :destroy, as: :user
has_many :organizations, through: :organization_users
default_value :expires_at, -> { 7.days.from_now }
@@ -41,16 +41,16 @@ class UserInvite < ApplicationRecord
def accept(user)
transaction do
self.organization_users.each do |ou|
ou.update(:user => user) || ou.destroy
organization_users.each do |ou|
ou.update(user: user) || ou.destroy
end
self.organization_users.reload
self.destroy
organization_users.reload
destroy
end
end
def reject
self.destroy
destroy
end
end

عرض الملف

@@ -24,19 +24,19 @@ class Webhook < ApplicationRecord
include HasUUID
belongs_to :server
has_many :webhook_events, :dependent => :destroy
has_many :webhook_events, dependent: :destroy
has_many :webhook_requests
validates :name, :presence => true
validates :url, :presence => true, :format => {:with => /\Ahttps?\:\/\/[a-z0-9\-\.\_\?\=\&\/\+:%@]+\z/i, :allow_blank => true}
validates :name, presence: true
validates :url, presence: true, format: { with: /\Ahttps?:\/\/[a-z0-9\-._?=&\/+:%@]+\z/i, allow_blank: true }
scope :enabled, -> { where(:enabled => true) }
scope :enabled, -> { where(enabled: true) }
after_save :save_events
when_attribute :all_events, :changes_to => true do
when_attribute :all_events, changes_to: true do
after_save do
self.webhook_events.destroy_all
webhook_events.destroy_all
end
end
@@ -49,12 +49,12 @@ class Webhook < ApplicationRecord
end
def save_events
if @events
return unless @events
@events.each do |event|
webhook_events.where(:event => event).first_or_create!
end
webhook_events.where.not(:event => @events).destroy_all
webhook_events.where(event: event).first_or_create!
end
webhook_events.where.not(event: @events).destroy_all
end
end

عرض الملف

@@ -15,18 +15,18 @@
class WebhookEvent < ApplicationRecord
EVENTS = [
'MessageSent',
'MessageDelayed',
'MessageDeliveryFailed',
'MessageHeld',
'MessageBounced',
'MessageLinkClicked',
'MessageLoaded',
'DomainDNSError'
"MessageSent",
"MessageDelayed",
"MessageDeliveryFailed",
"MessageHeld",
"MessageBounced",
"MessageLinkClicked",
"MessageLoaded",
"DomainDNSError"
]
belongs_to :webhook
validates :event, :presence => true
validates :event, presence: true
end

عرض الملف

@@ -19,17 +19,17 @@ class WebhookRequest < ApplicationRecord
include HasUUID
RETRIES = {1 => 2.minutes, 2 => 3.minutes, 3 => 6.minutes, 4 => 10.minutes, 5 => 15.minutes}
RETRIES = { 1 => 2.minutes, 2 => 3.minutes, 3 => 6.minutes, 4 => 10.minutes, 5 => 15.minutes }
belongs_to :server
belongs_to :webhook, :optional => true
belongs_to :webhook, optional: true
validates :url, :presence => true
validates :event, :presence => true
validates :url, presence: true
validates :event, presence: true
serialize :payload, Hash
after_commit :queue, :on => :create
after_commit :queue, on: :create
def self.trigger(server, event, payload = {})
unless server.is_a?(Server)
@@ -38,52 +38,52 @@ class WebhookRequest < ApplicationRecord
webhooks = server.webhooks.enabled.includes(:webhook_events).references(:webhook_events).where("webhooks.all_events = ? OR webhook_events.event = ?", true, event)
webhooks.each do |webhook|
server.webhook_requests.create!(:event => event, :payload => payload, :webhook => webhook, :url => webhook.url)
server.webhook_requests.create!(event: event, payload: payload, webhook: webhook, url: webhook.url)
end
end
def self.requeue_all
where("retry_after < ?", Time.now).each(&:queue)
where("retry_after < ?", Time.now).find_each(&:queue)
end
def queue
WebhookDeliveryJob.queue(:main, :id => self.id)
WebhookDeliveryJob.queue(:main, id: id)
end
def deliver
logger = Postal.logger_for(:webhooks)
payload = {:event => self.event, :timestamp => self.created_at.to_f, :payload => self.payload, :uuid => self.uuid}.to_json
logger.info "[#{id}] Sending webhook request to `#{self.url}`"
result = Postal::HTTP.post(self.url, :sign => true, :json => payload, :timeout => 5)
payload = { event: event, timestamp: created_at.to_f, payload: self.payload, uuid: uuid }.to_json
logger.info "[#{id}] Sending webhook request to `#{url}`"
result = Postal::HTTP.post(url, sign: true, json: payload, timeout: 5)
self.attempts += 1
self.retry_after = RETRIES[self.attempts]&.from_now
self.server.message_db.webhooks.record(
:event => self.event,
:url => self.url,
:webhook_id => self.webhook_id,
:attempt => self.attempts,
:timestamp => Time.now.to_f,
:payload => self.payload.to_json,
:uuid => self.uuid,
:status_code => result[:code],
:body => result[:body],
:will_retry => (self.retry_after ? 0 : 1)
server.message_db.webhooks.record(
event: event,
url: url,
webhook_id: webhook_id,
attempt: self.attempts,
timestamp: Time.now.to_f,
payload: self.payload.to_json,
uuid: uuid,
status_code: result[:code],
body: result[:body],
will_retry: (retry_after ? 0 : 1)
)
if result[:code] >= 200 && result[:code] < 300
logger.info "[#{id}] -> Received #{result[:code]} status code. That's OK."
self.destroy
self.webhook&.update_column(:last_used_at, Time.now)
destroy
webhook&.update_column(:last_used_at, Time.now)
true
else
logger.error "[#{id}] -> Received #{result[:code]} status code. That's not OK."
self.error = "Couldn't send to URL. Code received was #{result[:code]}"
if self.retry_after
logger.info "[#{id}] -> Will retry #{self.retry_after} (this was attempt #{self.attempts})"
self.save
if retry_after
logger.info "[#{id}] -> Will retry #{retry_after} (this was attempt #{self.attempts})"
save
else
logger.info "[#{id}] -> Have tried #{self.attempts} times. Giving up."
self.destroy
destroy
end
false
end

عرض الملف

@@ -1,3 +1,3 @@
#!/usr/bin/env ruby
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
load Gem.bin_path('bundler', 'bundle')
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
load Gem.bin_path("bundler", "bundle")

عرض الملف

@@ -1,4 +1,4 @@
#!/usr/bin/env ruby
APP_PATH = File.expand_path('../config/application', __dir__)
require_relative '../config/boot'
require 'rails/commands'
APP_PATH = File.expand_path("../config/application", __dir__)
require_relative "../config/boot"
require "rails/commands"

عرض الملف

@@ -1,4 +1,4 @@
#!/usr/bin/env ruby
require_relative '../config/boot'
require 'rake'
require_relative "../config/boot"
require "rake"
Rake.application.run

عرض الملف

@@ -1,10 +1,10 @@
#!/usr/bin/env ruby
require 'pathname'
require 'fileutils'
require "pathname"
require "fileutils"
include FileUtils
# path to your application root.
APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
APP_ROOT = Pathname.new File.expand_path("..", __dir__)
def system!(*args)
system(*args) || abort("\n== Command #{args} failed ==")
@@ -14,9 +14,9 @@ chdir APP_ROOT do
# This script is a starting point to setup your application.
# Add necessary setup steps to this file.
puts '== Installing dependencies =='
system! 'gem install bundler --conservative'
system('bundle check') || system!('bundle install')
puts "== Installing dependencies =="
system! "gem install bundler --conservative"
system("bundle check") || system!("bundle install")
# puts "\n== Copying sample files =="
# unless File.exist?('config/database.yml')
@@ -24,11 +24,11 @@ chdir APP_ROOT do
# end
puts "\n== Preparing database =="
system! 'bin/rails db:setup'
system! "bin/rails db:setup"
puts "\n== Removing old logs and tempfiles =="
system! 'bin/rails log:clear tmp:clear'
system! "bin/rails log:clear tmp:clear"
puts "\n== Restarting application server =="
system! 'bin/rails restart'
system! "bin/rails restart"
end

عرض الملف

@@ -1,10 +1,10 @@
#!/usr/bin/env ruby
require 'pathname'
require 'fileutils'
require "pathname"
require "fileutils"
include FileUtils
# path to your application root.
APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
APP_ROOT = Pathname.new File.expand_path("..", __dir__)
def system!(*args)
system(*args) || abort("\n== Command #{args} failed ==")
@@ -14,16 +14,16 @@ chdir APP_ROOT do
# This script is a way to update your development environment automatically.
# Add necessary update steps to this file.
puts '== Installing dependencies =='
system! 'gem install bundler --conservative'
system('bundle check') || system!('bundle install')
puts "== Installing dependencies =="
system! "gem install bundler --conservative"
system("bundle check") || system!("bundle install")
puts "\n== Updating database =="
system! 'bin/rails db:migrate'
system! "bin/rails db:migrate"
puts "\n== Removing old logs and tempfiles =="
system! 'bin/rails log:clear tmp:clear'
system! "bin/rails log:clear tmp:clear"
puts "\n== Restarting application server =="
system! 'bin/rails restart'
system! "bin/rails restart"
end

عرض الملف

@@ -1,5 +1,5 @@
# This file is used by Rack-based servers to start the application.
require_relative 'config/environment'
$0="[postal] #{ENV['PROC_NAME']}"
require_relative "config/environment"
$0 = "[postal] #{ENV.fetch('PROC_NAME', nil)}"
run Rails.application

عرض الملف

@@ -1,4 +1,4 @@
require_relative 'boot'
require_relative "boot"
require "rails"
require "active_model/railtie"
@@ -14,6 +14,7 @@ Bundler.require(*Rails.groups)
module Postal
class Application < Rails::Application
# Disable most generators
config.generators do |g|
g.orm :active_record
@@ -27,12 +28,13 @@ module Postal
config.eager_load_namespaces << Postal
# Disable field_with_errors
config.action_view.field_error_proc = Proc.new { |t, i| t }
config.action_view.field_error_proc = proc { |t, i| t }
# Load the tracking server middleware
require 'postal/tracking_middleware'
require "postal/tracking_middleware"
config.middleware.use Postal::TrackingMiddleware
config.logger = Postal.logger_for(:rails)
end
end

عرض الملف

@@ -1,11 +1,11 @@
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
$stdout.sync = true
$stderr.sync = true
require 'bundler/setup' # Set up gems listed in the Gemfile.
require "bundler/setup" # Set up gems listed in the Gemfile.
require_relative '../lib/postal/config'
require_relative "../lib/postal/config"
Postal.check_config!
ENV['RAILS_ENV'] = Postal.config.rails&.environment || 'development'
ENV["RAILS_ENV"] = Postal.config.rails&.environment || "development"

عرض الملف

@@ -1,26 +1,26 @@
module Clockwork
configure do |config|
config[:tz] = 'UTC'
config[:tz] = "UTC"
config[:logger] = Postal.logger_for(:cron)
end
every 1.minute, 'every-1-minutes' do
every 1.minute, "every-1-minutes" do
RequeueWebhooksJob.queue(:main)
SendNotificationsJob.queue(:main)
end
every 1.hour, 'every-hour', :at => ['**:15'] do
every 1.hour, "every-hour", at: ["**:15"] do
CheckAllDNSJob.queue(:main)
ExpireHeldMessagesJob.queue(:main)
CleanupAuthieSessionsJob.queue(:main)
end
every 1.hour, 'every-hour', :at => ['**:45'] do
every 1.hour, "every-hour", at: ["**:45"] do
PruneWebhookRequestsJob.queue(:main)
end
every 1.day, 'every-day', :at => ['03:00'] do
every 1.day, "every-day", at: ["03:00"] do
ProcessMessageRetentionJob.queue(:main)
PruneSuppressionListsJob.queue(:main)
end

عرض الملف

@@ -1,5 +1,5 @@
# Load the Rails application.
require_relative 'application'
require_relative "application"
# Initialize the Rails application.
Rails.application.initialize!

عرض الملف

@@ -13,12 +13,12 @@ Rails.application.configure do
config.consider_all_requests_local = true
# Enable/disable caching. By default caching is disabled.
if Rails.root.join('tmp/caching-dev.txt').exist?
if Rails.root.join("tmp/caching-dev.txt").exist?
config.action_controller.perform_caching = true
config.cache_store = :memory_store
config.public_file_server.headers = {
'Cache-Control' => 'public, max-age=172800'
"Cache-Control" => "public, max-age=172800"
}
else
config.action_controller.perform_caching = false

عرض الملف

@@ -34,7 +34,6 @@ Rails.application.configure do
# config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
# config.force_ssl = true
@@ -43,7 +42,7 @@ Rails.application.configure do
config.log_level = :info
# Prepend all log lines with the following tags.
config.log_tags = [ :request_id ]
config.log_tags = [:request_id]
# Use a different cache store in production.
# config.cache_store = :mem_cache_store
@@ -65,7 +64,7 @@ Rails.application.configure do
config.active_support.deprecation = :notify
# Use default logging formatter so that PID and timestamp are not suppressed.
config.log_formatter = ::Logger::Formatter.new
config.log_formatter = Logger::Formatter.new
# Use a different logger for distributed setups.
# require 'syslog/logger'

عرض الملف

@@ -15,7 +15,7 @@ Rails.application.configure do
# Configure public file server for tests with Cache-Control for performance.
config.public_file_server.enabled = true
config.public_file_server.headers = {
'Cache-Control' => 'public, max-age=3600'
"Cache-Control" => "public, max-age=3600"
}
# Show full error reports and disable caching.

عرض الملف

@@ -1,7 +1,7 @@
# Be sure to restart your server when you modify this file.
# Version of your assets, change this if you want to expire all your assets.
Rails.application.config.assets.version = '1.0'
Rails.application.config.assets.version = "1.0"
# Add additional assets to the asset load path
# Rails.application.config.assets.paths << Emoji.images_path

عرض الملف

@@ -12,13 +12,13 @@
# These inflection rules are supported but not enabled by default:
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.acronym 'API'
inflect.acronym 'SMTP'
inflect.acronym 'IP'
inflect.acronym 'DNS'
inflect.acronym 'UUID'
inflect.acronym 'HTTP'
inflect.acronym 'DB'
inflect.acronym 'MX'
inflect.acronym 'DKIM'
inflect.acronym "API"
inflect.acronym "SMTP"
inflect.acronym "IP"
inflect.acronym "DNS"
inflect.acronym "UUID"
inflect.acronym "HTTP"
inflect.acronym "DB"
inflect.acronym "MX"
inflect.acronym "DKIM"
end

عرض الملف

@@ -1,37 +1,38 @@
require 'mail'
require "mail"
module Mail
module Encodings
# Handle windows-1258 as windows-1252 when decoding
def Encodings.q_value_decode(str)
str = str.sub(/\=\?windows-?1258\?/i, '\=?windows-1252?')
def self.q_value_decode(str)
str = str.sub(/=\?windows-?1258\?/i, '\=?windows-1252?')
RubyVer.q_value_decode(str)
end
def Encodings.b_value_decode(str)
str = str.sub(/\=\?windows-?1258\?/i, '\=?windows-1252?')
def self.b_value_decode(str)
str = str.sub(/=\?windows-?1258\?/i, '\=?windows-1252?')
RubyVer.b_value_decode(str)
end
end
class Message
## Extract plain text body of message
def plain_body
if self.multipart? and self.text_part
self.text_part.decoded
elsif self.mime_type == 'text/plain' || self.mime_type.nil?
self.decoded
else
nil
if multipart? and text_part
text_part.decoded
elsif mime_type == "text/plain" || mime_type.nil?
decoded
end
end
## Extract HTML text body of message
def html_body
if self.multipart? and self.html_part
self.html_part.decoded
elsif self.mime_type == 'text/html'
self.decoded
else
nil
if multipart? and html_part
html_part.decoded
elsif mime_type == "text/html"
decoded
end
end
@@ -46,9 +47,21 @@ module Mail
# Returns the filename of the attachment (if it exists) or returns nil
# Make up a filename for rfc822 attachments if it isn't specified
def find_attachment
content_type_name = header[:content_type].filename rescue nil
content_disp_name = header[:content_disposition].filename rescue nil
content_loc_name = header[:content_location].location rescue nil
content_type_name = begin
header[:content_type].filename
rescue StandardError
nil
end
content_disp_name = begin
header[:content_disposition].filename
rescue StandardError
nil
end
content_loc_name = begin
header[:content_location].location
rescue StandardError
nil
end
if content_type && content_type_name
filename = content_type_name
@@ -56,56 +69,73 @@ module Mail
filename = content_disp_name
elsif content_location && content_loc_name
filename = content_loc_name
elsif self.mime_type == "message/rfc822"
filename = "#{rand(100000000)}.eml"
elsif mime_type == "message/rfc822"
filename = "#{rand(100_000_000)}.eml"
else
filename = nil
end
if filename
# Normal decode
filename = Mail::Encodings.decode_encode(filename, :decode) rescue filename
filename = begin
Mail::Encodings.decode_encode(filename, :decode)
rescue StandardError
filename
end
end
filename
end
def decode_body_as_text
body_text = decode_body
charset_tmp = Encoding.find(Ruby19.pick_encoding(charset)) rescue 'ASCII'
charset_tmp = 'Windows-1252' if charset_tmp.to_s =~ /windows-?1258/i
if charset_tmp == Encoding.find('UTF-7')
body_text.force_encoding('UTF-8')
decoded = body_text.gsub(/\+.*?\-/m) {|n|Base64.decode64(n[1..-2]+'===').force_encoding('UTF-16BE').encode('UTF-8')}
charset_tmp = begin
Encoding.find(Ruby19.pick_encoding(charset))
rescue StandardError
"ASCII"
end
charset_tmp = "Windows-1252" if charset_tmp.to_s =~ /windows-?1258/i
if charset_tmp == Encoding.find("UTF-7")
body_text.force_encoding("UTF-8")
decoded = body_text.gsub(/\+.*?-/m) { |n| Base64.decode64(n[1..-2] + "===").force_encoding("UTF-16BE").encode("UTF-8") }
else
body_text.force_encoding(charset_tmp)
decoded = body_text.encode("utf-8", :invalid => :replace, :undef => :replace)
decoded = body_text.encode("utf-8", invalid: :replace, undef: :replace)
end
decoded.valid_encoding? ? decoded : decoded.encode("utf-16le", :invalid => :replace, :undef => :replace).encode("utf-8")
decoded.valid_encoding? ? decoded : decoded.encode("utf-16le", invalid: :replace, undef: :replace).encode("utf-8")
end
end
# Handle attached emails as attachments
class AttachmentsList < Array
def initialize(parts_list)
@parts_list = parts_list
@content_disposition_type = 'attachment'
parts_list.map { |p|
@content_disposition_type = "attachment"
parts_list.map do |p|
(p.parts.empty? and p.attachment?) ? p : p.attachments
}.flatten.compact.each { |a| self << a }
end.flatten.compact.each { |a| self << a }
self
end
end
end
class Array
def decoded
return nil if self.empty?
return self.first.decoded
return nil if empty?
first.decoded
end
end
class NilClass
def decoded
nil
end
end

عرض الملف

@@ -1,2 +1,2 @@
require 'postal'
require 'postal/message_db/mysql'
require "postal"
require "postal/message_db/mysql"

عرض الملف

@@ -1,5 +1,6 @@
module ActionView
module RecordIdentifier
def dom_id(record, prefix = nil)
if record.new_record?
dom_class(record, prefix || NEW)
@@ -8,5 +9,6 @@ module ActionView
"#{dom_class(record, prefix)}#{JOIN}#{id}"
end
end
end
end

عرض الملف

@@ -1,6 +1,6 @@
if Postal.config.rails&.secret_key
Rails.application.secrets.secret_key_base = Postal.config.rails.secret_key
else
$stderr.puts "No secret key was specified in the Postal config file. Using one for just this session"
warn "No secret key was specified in the Postal config file. Using one for just this session"
Rails.application.secrets.secret_key_base = SecureRandom.hex(128)
end

عرض الملف

@@ -1,10 +1,8 @@
SecureHeaders::Configuration.default do |config|
config.hsts = SecureHeaders::OPT_OUT
config.csp[:default_src] = []
config.csp[:script_src] = ["'self'"]
config.csp[:child_src] = ["'self'"]
config.csp[:connect_src] = ["'self'"]
end

عرض الملف

@@ -1,14 +1,14 @@
require 'postal/config'
require "postal/config"
if Postal.config.general&.exception_url
require 'raven'
require "raven"
Raven.configure do |config|
config.dsn = Postal.config.general.exception_url
config.environments = ['production']
if ENV['DEV_EXCEPTIONS']
config.environments << 'development'
config.environments = ["production"]
if ENV["DEV_EXCEPTIONS"]
config.environments << "development"
end
config.silence_ready = true
config.tags = {:process => ENV['PROC_NAME']}
config.tags = { process: ENV.fetch("PROC_NAME", nil) }
end
end

عرض الملف

@@ -1,3 +1,3 @@
# Be sure to restart your server when you modify this file.
Rails.application.config.session_store :cookie_store, key: '_postal_session'
Rails.application.config.session_store :cookie_store, key: "_postal_session"

عرض الملف

@@ -1,5 +1,5 @@
require 'postal/config'
require "postal/config"
if Postal.config&.smtp
ActionMailer::Base.delivery_method = :smtp
ActionMailer::Base.smtp_settings = {:address => Postal.config.smtp.host, :user_name => Postal.config.smtp.username, :password => Postal.config.smtp.password, :port => Postal.config.smtp.port || 25}
ActionMailer::Base.smtp_settings = { address: Postal.config.smtp.host, user_name: Postal.config.smtp.username, password: Postal.config.smtp.password, port: Postal.config.smtp.port || 25 }
end

عرض الملف

@@ -1,10 +1,13 @@
class Net::SMTP::Response
def message
@string
end
end
class Net::SMTP
attr_accessor :source_address
def secure_socket?
@@ -19,7 +22,7 @@ class Net::SMTP
#
def rset
@error_occurred = false
getok('RSET')
getok("RSET")
end
def rset_errors
@@ -29,6 +32,7 @@ class Net::SMTP
private
def tcp_socket(address, port)
TCPSocket.open(address, port, self.source_address)
TCPSocket.open(address, port, source_address)
end
end

عرض الملف

@@ -1,9 +1,13 @@
module Rack
class Request
module Helpers
def trusted_proxy?(ip)
ip =~ /^127\.0\.0\.1$|^localhost$|^unix$$/i
end
end
end
end

عرض الملف

@@ -1,9 +1,9 @@
require_relative '../lib/postal/config'
require_relative "../lib/postal/config"
threads_count = Postal.config.web_server&.max_threads&.to_i || 5
threads threads_count, threads_count
bind_address = Postal.config.web_server&.bind_address || '127.0.0.1'
bind_port = Postal.config.web_server&.port&.to_i || ENV['PORT'] || 5000
bind_address = Postal.config.web_server&.bind_address || "127.0.0.1"
bind_port = Postal.config.web_server&.port&.to_i || ENV["PORT"] || 5000
bind "tcp://#{bind_address}:#{bind_port}"
environment Postal.config.rails&.environment || 'development'
environment Postal.config.rails&.environment || "development"
prune_bundler
quiet false

لم تُعرض بعض الملفات لأن الكثير من الملفات تغيرت في هذا الاختلاف إظهار المزيد