# Instance-level metadata for an exploit Metasploit Module
class Metasploit::Cache::Exploit::Instance < ActiveRecord::Base
  extend ActiveSupport::Autoload

  include Metasploit::Cache::Batch::Root

  autoload :Persister
  autoload :ExploitClass

  #
  #
  # Associations
  #
  #

  # Code contributions to this exploit Metasploit Module.
  has_many :contributions,
           as: :contributable,
           autosave: true,
           class_name: 'Metasploit::Cache::Contribution',
           dependent: :destroy,
           inverse_of: :contributable

  # The default {#exploit_targets exploit target}.
  belongs_to :default_exploit_target,
             class_name: 'Metasploit::Cache::Exploit::Target',
             inverse_of: :exploit_instance

  # The class level metadata for this exploit Metasploit Module
  belongs_to :exploit_class,
             class_name: 'Metasploit::Cache::Exploit::Class',
             foreign_key: :exploit_class_id,
             inverse_of: :exploit_instance

  # The targets that specialize this exploit for a given set of architectures and platforms.
  has_many :exploit_targets,
           autosave: true,
           class_name: 'Metasploit::Cache::Exploit::Target',
           dependent: :destroy,
           foreign_key: :exploit_instance_id,
           inverse_of: :exploit_instance

  # Joins {#licenses} to this exploit Metasploit Module.
  has_many :licensable_licenses,
           as: :licensable,
           autosave: true,
           class_name: 'Metasploit::Cache::Licensable::License',
           dependent: :destroy,
           inverse_of: :licensable

  # Joins {#references} to this exploit Metasploit Module.
  has_many :referencable_references,
           as: :referencable,
           autosave: true,
           class_name: 'Metasploit::Cache::Referencable::Reference',
           dependent: :destroy,
           inverse_of: :referencable

  #
  # through: :licensable_licenses
  #

  # The {Metasploit::Cache::License} for the code in this exploit Metasploit Module.
  has_many :licenses,
           class_name: 'Metasploit::Cache::License',
           through: :licensable_licenses

  #
  # through: :referencable_references
  #

  # The {Metasploit::Cache::Reference} for the content in this auxiliary Metasploit Module.
  has_many :references,
           class_name: 'Metasploit::Cache::Reference',
           through: :referencable_references

  #
  # Attributes
  #

  # @!attribute description
  #   The long-form human-readable description of this exploit Metasploit Module.
  #
  #   @return [String]

  # @!attribute disclosed_on
  #   The public disclosure date of this exploit.
  #
  #   @return [Date]

  # @!attribute exploit_class_id
  #   The foreign key for the {#exploit_class} association.
  #
  #   @return [Integer]

  # @!attribute name
  #   The human-readable name of this exploit Metasploit Module.  This can be thought of as the title or summary of
  #   the Metasploit Module.
  #
  #   @return [String]

  # @!attribute privileged
  #   Whether this exploit grants privileged access to the remote machine.
  #
  #   @return [true] privileged access is granted.
  #   @return [false] privileged access is NOT granted.

  # @!attribute stance
  #   Whether this Metasploit Module is aggressive or passive,
  #
  #   @return ['aggressive'] This Metasploit Module connects to a remote server, so the Metasploit Module is a client
  #     exploiting a server.
  #   @return ['passive'] This Metasploit Module waits for remote clients to connect to it, so the Metasploit Module is
  #     a server exploiting clients.

  #
  # Validations
  #

  validates :contributions,
            length: {
                minimum: 1
            }

  validates :default_exploit_target,
            inclusion: {
                allow_nil: true,
                in: ->(exploit_instance){
                  exploit_instance.exploit_targets
                }
            }

  validates :description,
            presence: true

  validates :disclosed_on,
            presence: true

  validates :exploit_class,
            presence: true

  validates :exploit_class_id,
            uniqueness: {
                unless: :batched?
            }

  validates :exploit_targets,
            length: {
                minimum: 1
            }

  validates :licensable_licenses,
            length: {
              minimum: 1
            }

  validates :name,
            presence: true

  validates :privileged,
            inclusion: {
                in: [
                    false,
                    true
                ]
            }

  validates :referencable_references,
            length: {
              minimum: 1
            }

  validates :stance,
            inclusion: {
                in: Metasploit::Cache::Module::Stance::ALL
            }

  Metasploit::Concern.run(self)
end