# frozen_string_literal: true
#
# ronin-recon - A micro-framework and tool for performing reconnaissance.
#
# Copyright (c) 2023-2024 Hal Brodigan (postmodern.mod3@gmail.com)
#
# ronin-recon 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-recon 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-recon. If not, see .
#
require 'set'
module Ronin
module Recon
#
# Represents a directed graph of discovered values and their parent values.
#
class Graph
# The nodes in the graph.
#
# @return [Set]
attr_reader :nodes
# The edges between nodes in the graph.
#
# @return [Hash{Value => Set}]
attr_reader :edges
#
# Initializes the graph.
#
# @api private
#
def initialize
@nodes = Set.new
@edges = {}
end
#
# Adds a value to the graph, if it already hasn't been added.
#
# @param [Values::Value] new_value
# The new value node to add.
#
# @return [Boolean]
# Indicates whether the value node was successfully added to the graph,
# or if the value node was already added to the graph.
#
# @api private
#
def add_node(new_value)
!@nodes.add?(new_value).nil?
end
#
# Adds a value to the graph, if it already hasn't been added.
#
# @param [Values::Value] new_value
# The new value node to add.
#
# @param [Value, nil] parent_value
# The parent value node of the new value node.
#
# @return [Boolean]
# Indicates whether the value node was successfully added to the graph,
# or if the value node was already added to the graph.
#
# @api private
#
def add_edge(new_value,parent_value)
if parent_value
node_parents = (@edges[new_value] ||= Set.new)
return !node_parents.add?(parent_value).nil?
end
end
#
# Determines if the value is in the graph.
#
# @param [Values::Value] value
# The value node.
#
# @return [Boolean]
# Indicates whether the value exists in the graph or not.
#
def include?(value)
@nodes.include?(value)
end
#
# Fetches the parent value nodes for the value.
#
# @param [Values::Value] value
# The value node to lookup.
#
# @return [Set, nil]
# The set of parent value nodes or `nil` if the value does not exist in
# the graph.
#
def [](value)
@edges[value]
end
#
# Determines if the graph is empty.
#
# @return [Boolean]
#
def empty?
@nodes.empty?
end
end
end
end