1
0
مراية لـ https://github.com/postalserver/postal.git تم المزامنة 2025-11-30 21:32:30 +00:00
الملفات
postal/app/models/domain.rb
Adam Cooke 1a4158699c refactor: refactor DNS resolution
This commit also adds some of tests for the Domain model. It was during the writing of these tests that the DNS resolution refactoring requirement became apparent.
2024-02-23 22:51:34 +00:00

172 أسطر
4.4 KiB
Ruby

# frozen_string_literal: true
# == Schema Information
#
# Table name: domains
#
# id :integer not null, primary key
# server_id :integer
# uuid :string(255)
# name :string(255)
# verification_token :string(255)
# verification_method :string(255)
# verified_at :datetime
# dkim_private_key :text(65535)
# created_at :datetime
# updated_at :datetime
# dns_checked_at :datetime
# spf_status :string(255)
# spf_error :string(255)
# dkim_status :string(255)
# dkim_error :string(255)
# mx_status :string(255)
# mx_error :string(255)
# return_path_status :string(255)
# return_path_error :string(255)
# outgoing :boolean default(TRUE)
# incoming :boolean default(TRUE)
# owner_type :string(255)
# owner_id :integer
# dkim_identifier_string :string(255)
# use_for_any :boolean
#
# Indexes
#
# index_domains_on_server_id (server_id)
# index_domains_on_uuid (uuid)
#
require "resolv"
class Domain < ApplicationRecord
include HasUUID
include HasDNSChecks
VERIFICATION_EMAIL_ALIASES = %w[webmaster postmaster admin administrator hostmaster].freeze
VERIFICATION_METHODS = %w[DNS Email].freeze
belongs_to :server, optional: true
belongs_to :owner, optional: true, polymorphic: true
has_many :routes, dependent: :destroy
has_many :track_domains, dependent: :destroy
validates :name, presence: true, format: { with: /\A[a-z0-9\-.]*\z/ }, uniqueness: { case_sensitive: false, 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
before_create :generate_dkim_key
scope :verified, -> { where.not(verified_at: nil) }
when_attribute :verification_method, changes_to: :anything do
before_save do
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
end
end
def verified?
verified_at.present?
end
def mark_as_verified
return false if verified?
self.verified_at = Time.now
save!
end
def parent_domains
parts = name.split(".")
parts[0, parts.size - 1].each_with_index.map do |_, i|
parts[i..].join(".")
end
end
def generate_dkim_key
self.dkim_private_key = OpenSSL::PKey::RSA.new(1024).to_s
end
def dkim_key
return nil unless dkim_private_key
@dkim_key ||= OpenSSL::PKey::RSA.new(dkim_private_key)
end
def to_param
uuid
end
def verification_email_addresses
parent_domains.map do |domain|
VERIFICATION_EMAIL_ALIASES.map do |a|
"#{a}@#{domain}"
end
end.flatten
end
def spf_record
"v=spf1 a mx include:#{Postal.config.dns.spf_include} ~all"
end
def dkim_record
return if dkim_key.nil?
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
return nil unless dkim_identifier_string
Postal.config.dns.dkim_identifier + "-#{dkim_identifier_string}"
end
def dkim_record_name
identifier = dkim_identifier
return if identifier.nil?
"#{identifier}._domainkey"
end
def return_path_domain
"#{Postal.config.dns.custom_return_path_prefix}.#{name}"
end
# Returns a DNSResolver instance that can be used to perform DNS lookups needed for
# the verification and DNS checking for this domain.
#
# @return [DNSResolver]
def resolver
return DNSResolver.local if Postal.config.general.use_local_ns_for_domains?
@resolver ||= DNSResolver.for_domain(name)
end
def dns_verification_string
"#{Postal.config.dns.domain_verify_prefix} #{verification_token}"
end
def verify_with_dns
return false unless verification_method == "DNS"
result = resolver.txt(name)
if result.include?(dns_verification_string)
self.verified_at = Time.now
return save
end
false
end
end