# frozen_string_literal: true # # ronin-db-activerecord - ActiveRecord backend for the Ronin Database. # # Copyright (c) 2022-2023 Hal Brodigan (postmodern.mod3 at gmail.com) # # ronin-db-activerecord is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published # by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # ronin-db-activerecord is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with ronin-db-activerecord. If not, see . # require 'ronin/db/model' require 'ronin/db/model/importable' require 'active_record' require 'digest' module Ronin module DB # # Represents a password used by {Service services} or {URL websites}. # class Password < ActiveRecord::Base include Model include Model::Importable # @!attribute [rw] id # The primary key of the password. # # @return [Integer] attribute :id, :integer # @!attribute [rw] plain_text # The clear-text of the password. # # @return [String] attribute :plain_text, :string # length: 256, validates :plain_text, presence: true, uniqueness: true # @!attribute [rw] credentials # The credentials which use the password. # # @return [Array] has_many :credentials, dependent: :destroy # @!attribute [rw] user_names # The user names which use the password. # # @return [Array] has_many :user_names, through: :credentials # # Looks up the password. # # @param [#to_s] password # The password to lookup. # # @return [Password, nil] # The found password. # # @api public # def self.lookup(password) find_by(plain_text: password.to_s) end # # Parses a password. # # @param [#to_s] password # The password to import. # # @return [Password] # The imported password. # # @api public # def self.import(password) create(plain_text: password.to_s) end # # Hashes the password. # # @param [Symbol, String] algorithm # The digest algorithm to use. # # @param [String, nil] prepend_salt # The salt data to prepend to the password. # # @param [String, nil] append_salt # The salt data to append to the password. # # @return [String] # The hex-digest of the hashed password. # # @raise [ArgumentError] # Unknown Digest algorithm. # # @example # pass = Password.new(plain_text: 'secret') # # pass.digest(:sha1) # # => "e5e9fa1ba31ecd1ae84f75caaa474f3a663f05f4" # # pass.digest(:sha1, prepend_salt: "A\x90\x00") # # => "e2817656a48c49f24839ccf9295b389d8f985904" # # pass.digest(:sha1, append_salt: "BBBB") # # => "aa6ca21e446d425fc044bbb26e950a788444a5b8" # # @api public # def digest(algorithm, prepend_salt: nil, append_salt: nil) digest_class = begin Digest.const_get(algorithm.upcase) rescue LoadError raise(ArgumentError,"Unknown Digest algorithm #{algorithm}") end hash = digest_class.new hash << prepend_salt.to_s if prepend_salt hash << self.plain_text hash << append_salt.to_s if append_salt return hash.hexdigest end # # The number of credentials which use this password. # # @return [Integer] # The number of credentials that use the password. # # @api public # def count self.credentials.count end # # Converts the password into a String. # # @return [String] # The clear-text of the password. # # @api public # def to_s self.plain_text end end end end require 'ronin/db/credential'