How to know which class member function is called? - ruby

From https://github.com/rapid7/metasploit-framework/blob/master/modules/auxiliary/scanner/smtp/smtp_version.rb#L26:
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::Smtp
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report
def initialize
super(
'Name' => 'SMTP Banner Grabber',
'Description' => 'SMTP Banner Grabber',
'References' =>
[
['URL', 'http://www.ietf.org/rfc/rfc2821.txt'],
],
'Author' => 'CG',
'License' => MSF_LICENSE
)
deregister_options('MAILFROM', 'MAILTO')
end
def run_host(ip)
res = connect
banner_sanitized = Rex::Text.to_hex_ascii(banner.to_s)
print_good("#{ip}:#{rport} SMTP #{banner_sanitized}")
report_service(:host => rhost, :port => rport, :name => "smtp", :info => banner)
end
end
I see connect is called above. Is connect a member function? How to know the member function of which super class is called? Thanks.

Most Likely an Inherited or Included Method
You didn't post all the relevant code, so you'd have to go spelunking in the rest of the source to be sure. I'm only going to address the section you specifically addressed.
In the small example you linked to, #connect is probably inherited from Msf::Auxiliary, or one of the included modules. From the name, it's most likely from Msf::Exploit::Remote::Smtp, but I didn't research it for you.
The reason it's most likely a method is that your current class isn't taking a connect argument anywhere. Since Ruby expressions essentially allow you to use method calls like right-hand side assignment values, this is a common idiom.
If you want to know for sure, grep your source for def connect to find where it's defined (assuming it's not done through something more meta like Module#define_method), or /\bconnect\b/ to find all the locations in your source tree where you might want to look more closely for its use or definition.

Related

How to rspec test a Puppet class when a parameter needs a resource reference

This may be a simple matter of mocking a resource, but...
class myclass (
String stringParam,
Integer intParam,
File fileParam
) {
# do some things
$path = fileParam['title']
$mode = fileParam['mode']
# do some more things
}
Now I want to write an rspec-puppet test for this class. How do I either create or mock a File resource and get it into the catalog that rspec-puppet uses, so that I can reference it?
The answers to this and this got me partway there, but everything I've tried has led to myClass complaining that it's being passed a string instead of a file reference.
...
let(:params) {{
:stringParam => 'Here is my string',
:intParam => 238,
:fileParam => *??????,*
}}
There isn't really much support in rspec-puppet for this, as a class test parameters list is generated from the :params assuming only strings (or nested hashes/arrays etc. containing strings) or a couple of permitted symbol values used almost literally, :undef and :default. It doesn't have a way of passing in resource references.
A workaround exists that lets you put literal content into a manifest though, by passing an object that responds to the inspect method. For example, in your spec_helper.rb:
class ResourceReference
def initialize(ref)
#ref = ref
end
def inspect
#ref
end
end
And then in your spec:
let(:params) {{
:stringParam => 'Here is my string',
:intParam => 238,
:fileParam => ResourceReference.new("File[/etc/foo]"),
}}
rspec-puppet will call the inspect method on the ResourceReference object which returns the string you've passed in. This should be placed in the manifest unchanged.
(This was originally used as a workaround for undef, which can now be passed as :undef.)
As an aside, you can set let(:pre_condition) { "..." } to add literal content to the test manifest before the generated class { ... }, but I don't think there's a way to use that here.
I'd strongly recommend filing a feature request against rspec-puppet.

How to use .tap method to build associated record?

I have an omniauth authentication model I'm building that's associated to a user.
aka user has many authentications.
I wish to build up key-value pairs of this authentication models using tap because twitter provides a secret key while facebook does not.
So if I have this, I want to accomplish the following conditional statement using the .tap method instead.
class User < ActiveRecord::Base
def apply_omniauth(omni)
if omni['credentials']['secret']
self.authentications.build(:provider => omni['provider'],
:uid => omni['uid'],
:token => omni['credentials']['token'],
:token_secret => omni['credentials']['secret']
else
self.authentications.build(:provider => omni['provider'],
:uid => omni['uid'],
:token => omni['credentials']['token']
end
end
end
UPDATE:
I'm trying it this way. Does this accomplish the same as the above?
self.authentications.build.tap do |auth|
auth[:provider] = omni['provider'] if omni['provider']
auth[:uid] = omni['uid'] if omni['uid']
auth[:token] = omni['credentials']['token'] if omni['credentials']['token']
auth[:token_secret] = omni['credentials']['secret'] if omni['credentials']['secret']
end
I think you could simply do (self is obsolete here):
authentications.build(:provider => omni['provider'],
:uid => omni['uid'],
:token => omni['credentials']['token'],
:token_secret => omni['credentials']['secret'])
If any key is missing, this will simply assign nil value. Unless you have some custom logic for setting those attributes, there is no difference between assigning nil or not assigning anything for a new records.

Chef Recipes - Setting node attributes in ruby_block

I have a Chef recipe for a multi-node web service, each node of which needs to get the hostname and IP of the other nodes, to put it into its own local configuration.
The code is shown below. The problem is that when the node.set[][] assignments are made in the ruby_block as shown, the values are empty when the template that relies upon them is created. If I want to create that template, I have to move all of the ruby_block code outside, and have it "loose" in the recipe. Which makes it harder to do unit-testing with Chefspec and the like.
Can any Chef guru set me straight? Is it just impossible to do node.set[] like this inside of a ruby_block? And if so, why doesn't it say so in the docs?
$cm = { :name => "web", :hostname => "" , :ip_addr => "" }
$ca = { :name => "data", :hostname => "" , :ip_addr => "" }
$cg = { :name => "gateway", :hostname => "" , :ip_addr => "" }
$component_list = [$cm, $ca, $cg]
ruby_block "get host addresses" do
block do
for cmpnt in $component_list
# do REST calls to external service to get cmpnt.hostname, ip_addr
# .......
node.set[cmpnt.name]['name'] = cmpnt.name
node.set[cmpnt.name]['host'] = cmpnt.hostname
node.set[cmpnt.name]['ip'] = cmpnt.ip_addr
end
end
end
template "/etc/app/configuration/config.xml" do
source "config.xml.erb"
variables( :dataHost => node['data']['host'],
:webHost => node['web']['host'],
:gatewayHost => node['gateway']['host'] )
action :create
end
I also added
subscribes :create, "ruby_block[get host addresses]", :immediately
to the template definition to ensure that the ruby_block ran before the template was created. This didn't make a difference.
I realize this is an old post, however for future reference, I just ran across this gist which gives a nice example of node variable assignments in the Compile vs. Converge phases. To adapt the gist to your example, you'll need to add code like the following to your ruby_block:
template_r = run_context.resource_collection.find(:template => "/etc/app/configuration/config.xml")
template_r.content node['data']['host']
template_r.content node['web']['host']
template_r.content node['gateway']['host']
For Chef 11, also see Lazy Attribute Evaluation.
The problem seems to be that attribute values inside your template resource definition get evaluated before actually invoking any resources.
I.e. the file is first executed as simple Ruby, compiling the resources, and only the the resource actions gets invoked. By that time, it is too late already.
I ran into the same problem when trying to encapsulate certain attribute manipulations into a resource. It simply does not work. Should anyone know a solution to this problem, I would appreciate it very much.
EDIT:
b = ruby_block...
...
end
b.run_action(:create)
Could possibly do the trick. It invokes the resource immediately.
The simplest answer to this is to not use chef attributes and not use ruby_block to do the work of talking to the REST API. The code can also be moved to a custom resource for better reuse:
unified_mode true
provides :my_resource
action :run do
cm = { :name => "web", :hostname => "" , :ip_addr => "" }
ca = { :name => "data", :hostname => "" , :ip_addr => "" }
cg = { :name => "gateway", :hostname => "" , :ip_addr => "" }
component_list = [cm, ca, cg]
hash = {}
for cmpnt in component_list
# do REST calls to external service to get cmpnt.hostname, ip_addr
# .......
hash[cmpnt.name] = {}
hash[cmpnt.name]['name'] = cmpnt.name
hash[cmpnt.name]['host'] = cmpnt.hostname
hash[cmpnt.name]['ip'] = cmpnt.ip_addr
end
template "/etc/app/configuration/config.xml" do
source "config.xml.erb"
variables( :dataHost => hash['data']['host'],
:webHost => hash['web']['host'],
:gatewayHost => hash['gateway']['host'] )
action :create
end
end
By using unified_mode and moving into a custom resource, it also makes it easier to use a node attribute without requiring the use of lazy {} or ruby_blocks. It also still allows chef configuration (like setting up resolv.conf or other network requirements before doing the REST calls) prior to calling this code while not having to think about compile/converge two pass issues in recipe context.
There is also no reason to use a resource like ruby_block to do pure ruby processing which does not change the system under management. In this case the ruby_block is hitting a REST service purely to collect data. That does not need to be placed into a Chef resource. It isn't clear from the question if that was being done because the questioner though it was a "best practice" (in this case it is not), or if it was being done to move execution to compile time in order to allow other chef resources that aren't part of the question to fire first (in which case using a custom resource is a much better solution than using a ruby_block).
It's been a while since this question, but in case someone is still looking for it, lazy evaluate is your friend:
template '/tmp/sql_file.sql' do
source "sql_file.sql.erb"
mode 0700
variables lazy {
# Create a new instance of MySQL library
mysql_lib = Acx::MySQL.new(
'127.0.0.1', 'root', node['mysql']['service']['pass']
)
password = node['mysql']['service']['support_admin']['ct_password']
# It returns the encrypted password after evaluate it, to
# be used in template variables
{ admin_password: mysql_lib.encrypted_password(password) }
}
end
https://docs.chef.io/resource_common.html#lazy-evaluation

Sinatra: User.first method

I'm reading a book that's making a Twitter clone with Sinatra in order to improve my knowledge of Ruby. I'm puzzled by the author's use of
User.first(:nickname => params[:recipient])
which he uses in several locations throughout the code, as in the following example.
post '/message/send' do
recipient = User.first(:nickname => params[:recipient])
Status.create(:text => params[:message], :user => User.
get(session[:userid]), :recipient => recipient)
redirect '/messages/sent'
end
What exactly is 'first' adding to this method. For example, is it searching for the first user with the nickname passed in as the parameter :recipient? In other words, is it equivalent to 'find'?
I should add that it puzzles me also because the nicknames are supposed to be unique, so there's no reason why it would need to search for the 'first' if that's indeed what it's doing.
Update
The author is using DataMapper for the ORM
Ok, 'first' is a datamapper method that 'finds'. From the docs
zoo = Zoo.first(:name => 'Metro') # first matching record with the name 'Metro'

Using ActiveResource to manipulate another application's Database

I've come to seek your collective wisdom.
My goal, an overview:
In order to better manage computers for various clients, I'm attempting to extend Puppet's Dashboard. It's a Rails 2 application, and I'm trying to extend it with a Rails 3 application I'm writing. There are a few problems that make Dashboard less than perfect for my needs, but the solutions are simple. I'm going to focus on one, because I feel that the answer to this question will help me figure the rest out. I've been looking into solutions that don't alter the dashboard code at all, because I'm not the maintainer, and don't want to make a future mess.
I thought a lot about how to do this best. I thought about plugging directly into the database but I got cold feet after doing a little googling. It appears that setting up a second database connection isn't that difficult, the thing I don't like is altering another application's database while it's running. Please say something if I'm passing up a perfectly reasonable option, based on superstition.
There were a few other ideas, but the one that I started in on finally, and had marginal success with was accessing Dashboard's database via REST. It's built in, why not use it? Well, I was able to manipulate a couple of the tables, but not the one that I wanted to. So there are three tables to be aware of in this situation.
nodes (basically computers)
node_groups (the groups you can put computers in)
node_group_memberships (the join table that relates 1 and 2 to each other)
I can add and remove both nodes, and node_groups, but I want to be able to create a connection between the two as well. In order to create a new user, I have an ActiveResource model set up that looks like this:
class PuppetNode < ActiveResource::Base
self.site = "http://127.0.0.1:4000/"
self.element_name = "node"
attr_accessor :grouped
end
I'm then free to create new nodes, or grab info from the nodes table via the console. It might look something like this:
PuppetNode.create(:column_name => "and so on")
The same goes for node_groups, and I can even create a Rails 3 model that doesn't wig out for node_group_memberships, but I can't create anything in that table. I can see if I look at the Rails 2 node_group_membership controller (by the good folks over at Puppet Labs), that there is a create method
class NodeGroupMembershipsController < InheritedResources::Base
respond_to :json
before_filter :raise_if_enable_read_only_mode, :only => [:new, :edit, :create, :update, :destroy]
before_filter :standardize_post_data, :only => [:create]
def create
create! do |success, failure|
success.json { render :text => #node_group_membership.to_json, :content_type => 'application/json', :status => 201 }
failure.json { render :text => {}.to_json, :content_type => 'application/json', :status => 422 }
end
end
# we want: {node_group_membership => {node_id => <id>, node_group_id => <id>}
# allow and convert: {node_name => <name>, group_name => <name>}
def standardize_post_data
unless params[:node_group_membership]
params[:node_group_membership] = {}
node = Node.find_by_name(params[:node_name])
group = NodeGroup.find_by_name(params[:group_name])
params[:node_group_membership][:node_id] = (node && node.id)
params[:node_group_membership][:node_group_id] = (group && group.id)
end
end
end
But for whatever reason it chokes out every time I try to create an association with something like this
irb(main):005:0> PuppetNodeGroupMembership.create(:node_id => 20, :node_group_id => 5)
=> #<PuppetNodeGroupMembership:0x007fb3150af878 #attributes={"node_id"=>20, "node_group_id"=>5}, #prefix_options={}, #persisted=false, #remote_errors=#<ActiveResource::ResourceInvalid: Failed. Response code = 422. Response message = .>, #validation_context=nil, #errors=#<ActiveResource::Errors:0x007fb3150af4e0 #base=#<PuppetNodeGroupMembership:0x007fb3150af878 ...>, #messages={}>>
Any advice would be much appreciated, I've already put a solid 8 miserable hours into trying to figure it out. Thanks!
For better or for worse one thing that does work is connecting to a second database with the same Rails application. I'm leaving this marked as "An Answer" for now, but not "The Answer".
This is the resource that I found that helped me along:
http://www.rubynaut.net/articles/2008/05/31/how-to-access-multiple-database-in-rails.html

Resources