require 'database/dir_tree.rb' # The Transformer class is used to compile protections objects into protection trees class Transformer attr_accessor :calculated_ft def initialize(ft, prot) @ft = ft @calculated_ft = strip_tree(@ft.dup) @dtree = Dir_Tree.new @prot = prot end # Create a duplicate of ft, with all payloads removed # @param [Tree::TreeNode] ft File tree with payloads # @return [Tree::TreeNode] File tree without payloads (used to create calculated_ft) def strip_tree(ft) ft.each { |node| node.content = nil } return ft end # A method to loop through each user/group and calculate_protections_for_user def calculate_protections users_groups = @prot.find_users_and_groups users_groups.each { |user_group| calculate_protections_for_user(user_group) } end # Calculate the protections tree for the given user at all nodes, and merge to the current protection tree at # that node on the calculated_ft # @param [Array] user_group the user/group name along with user type # @exmple ['brett', 0] def calculate_protections_for_user(user_group) #Each node on the filetree @ft.each { |node| cft_node = nil if node == nil binding.pry end if node.is_root? cft_node = @calculated_ft else parentage_array = node.parentage.reverse parentage_array.shift cft_node = @calculated_ft parentage_array.each { |parent| cft_node = cft_node[parent.name] } if cft_node == nil next end cft_node = cft_node[node.name] end if cft_node == nil next end #Make an empty array if payload is empty if cft_node.content == nil cft_node.content = [Tree::TreeNode.new("0"),Tree::TreeNode.new("1")] end node_protections = hash_to_tree(find_nodes_protection(node, user_group)) if node_protections merge_to_tree(cft_node.content, node_protections) end } end # Converts a hash representation of a protection tree into a tree # @param [Hash{String => Hash{String => Hash{String => Integer}}}] hash Hash to convert # @return [Tree::TreeNode] Tree representation of input hash def hash_to_tree(hash) tree = nil if hash hash.each { |type,type_hash| tree = Tree::TreeNode.new(type.to_s) type_hash.each { |user, user_hash| tree << Tree::TreeNode.new(user.to_s) user_hash.each { |host, perm| tree[user] << Tree::TreeNode.new(host.to_s) tree[user][host] << Tree::TreeNode.new(perm.to_s) } } } else return nil end return tree end # Merge two protections trees (the nodes current payload and the nodes to update the tree with) # @param [Array] content Protection tree root (0/1) # @param [Array] node_protections The protections tree to apply to content # @return [Array] The updated version of content def merge_to_tree(content, node_protections) if content[node_protections.name.to_i].has_children? content_new = content.dup if content_new[node_protections.name.to_i] #content_new = type content_new = content_new[node_protections.name.to_i] if content_new[node_protections[0].name] #content_new = name content_new = content_new[node_protections[0].name] #content_new = host if content_new[node_protections[0][0].name] content_new = content_new[node_protections[0][0].name] #content_new = perm if content_new[node_protections[0][0][0].name] content_new = content_new[node_protections[0][0][0].name] else content_new = content.dup content_new[node_protections.name.to_i][node_protections[0].name][node_protections[0][0].name] << node_protections[0][0][0] end else content_new = content.dup content_new[node_protections.name.to_i][node_protections[0].name] << node_protections[0][0] end else content_new = content.dup content_new[node_protections.name.to_i] << node_protections[0] end else content_new = content.dup content_new << node_protections end else content_new = content.dup content_new[node_protections.name.to_i] << node_protections[0] end return content_new end # Create a list of protections which apply for the specified user, at the specified node # @param [Tree::TreeNode] node the node who's payload will be searched # @param [Array] user_group # @return [{user => [{level => level, host => host}]}] def find_nodes_protection(node, user_group) # prot_list = [] unless node.is_root? unless node.content == nil node.content.each { |protection| if regex_include_string?(protection.user,user_group[0]) prot_list << protection end } end node.parentage.each { |ancestor| unless ancestor.content == nil ancestor.content.each { |protection| if regex_include_string?(protection.user,user_group[0]) prot_list << protection end } end } else unless node.content == nil node.content.each {|protection| if regex_include_string?(protection.user,user_group[0]) prot_list << protection end } end end #Sort the list by sequence value prot_list.sort! { |a,b| a.seq <=> b.seq } return get_node_protection_for_user(user_group, prot_list) end # Filter a list of protections, for a name and type (name and type == user_group) # @param [Array] prot_list The array of protection objects to search through # @param [String] name user_group[0] # @param [Integer] type user_group[1] # @return [Array] The filtered protection list def filter_prot_list(prot_list, name, type) filtered_prot_list = [] prot_list.each{ |protection| if type == protection.is_group if regex_include_string?(protection.user.dup, name.dup) filtered_prot_list << protection end end } return filtered_prot_list end # Merges the output of {#filter_prot_list} into a single entity, using bitwise OR # @param [Array] prot_list List of all protections at a node # @return [Hash] a further cleaned version of out_node def get_node_protection_for_user(user_group, prot_list) name = user_group[0] type = user_group[1] host = {"*" => 0} name_host = {name => host} type_name = {type => name_host} #See page 27 out_node = type_name filtered_prot_list = filter_prot_list(prot_list, name, type) clean_filtered_prot_list(filtered_prot_list, out_node, type, name) return clean_structure(out_node) end # Cleans nodes of useless information i.e [{0=>{"max"=>{"*"=>0}}}] # @param [Hash] struct Structure to be cleaned # @return [Hash] The cleaned structure def clean_structure(struct) struct.each { |type, type_load| if type_load == nil return nil end type_load.each { |name, name_load| #TODO Is this clause needed? if name_load == nil return nil end name_load.each { |host, host_load| if host_load == 0 struct[type][name].delete(host) end unless struct[type][name][host] struct[type].delete(name) end } if name == nil return nil end } } if struct[0] == {} return nil else return struct end end # Test if s2 contains s1 # @param [String] s1 # @param [String] s2 # @return [True, nil] def regex_include_string?(s1, s2) subbed = s1.sub('*', "(.*)") s1_reg = Regexp.new(subbed) if s2 =~ s1_reg return true else return nil end end end