I am trying to fetch files from a server using FTPS. I'm able to authenticate but when I try to list/fetch the files, I get a "521 Data connections must be encrypted". Is the Net::FTP module capable of this, and how would I accomplish it?
I modified Net::FTPTLS into my own class because I needed to store a self-signed cert.
require 'socket'
require 'openssl'
require 'net/ftp'
module MP
class FTPS < Net::FTP
def connect(host, port=FTP_PORT)
#hostname = host
super
end
def login(user = "anonymous", passwd = nil, cert_file = nil, acct = nil)
store = OpenSSL::X509::Store.new
if cert_file == nil
store.set_default_paths
else
certraw = File.read(cert_file)
cert = OpenSSL::X509::Certificate.new(certraw)
store.add_cert(cert)
end
ctx = OpenSSL::SSL::SSLContext.new('SSLv23')
ctx.cert_store = store
ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
ctx.key = nil
ctx.cert = cert
voidcmd("AUTH TLS")
#sock = OpenSSL::SSL::SSLSocket.new(#sock, ctx)
#sock.connect
##sock.post_connection_check(#hostname)
super(user, passwd, acct)
voidcmd("PBSZ 0")
end
end
end
And here's the snippet for trying to fetch the files:
def get_ftpclient(host)
FTPS::new(host)
end
def check_for_files
#ftp = get_ftpclient(#host)
#ftp.passive = true
#ftp.login(#user_name, #password, #cert_file)
#ftp.chdir(#remote_dir)
files = #ftp.nlst
files
end
It fails on the nlst.
Edit: I tried adding voidcmd("PROT P") to the end of the login function but it just hangs for a while, then I eventually get:
IOError: Unsupported record version Unknown-48.48
___BEGIN BACKTRACE___
org/jruby/ext/openssl/SSLSocket.java:564:in `sysread'
/opt/jruby/lib/ruby/gems/1.8/gems/jruby-openssl-0.7.6.1/lib/1.8/openssl/buffering.rb:36:in `fill_rbuff'
/opt/jruby/lib/ruby/gems/1.8/gems/jruby-openssl-0.7.6.1/lib/1.8/openssl/buffering.rb:159:in `eof?'
/opt/jruby/lib/ruby/gems/1.8/gems/jruby-openssl-0.7.6.1/lib/1.8/openssl/buffering.rb:134:in `readline'
/opt/jruby/lib/ruby/1.8/net/ftp.rb:211:in `getline'
/opt/jruby/lib/ruby/1.8/net/ftp.rb:221:in `getmultiline'
/opt/jruby/lib/ruby/1.8/net/ftp.rb:235:in `getresp'
/opt/jruby/lib/ruby/1.8/net/ftp.rb:251:in `voidresp'
/opt/jruby/lib/ruby/1.8/net/ftp.rb:436:in `retrlines'
/opt/jruby/lib/ruby/1.8/monitor.rb:191:in `mon_synchronize'
/opt/jruby/lib/ruby/1.8/net/ftp.rb:422:in `retrlines'
/opt/jruby/lib/ruby/1.8/net/ftp.rb:612:in `nlst'
... etc
I realize this is an old question, but I stumbled upon it while researching FTPS ruby gems.
No. net::FTP does not, on its own, support FTPS.
I highly recommend double-bag-ftps.
Provides a child class of Net::FTP to support implicit and explicit FTPS.
Version 0.1.1 has been working beautifully for me running daily for the past year.
Related
I created a CLI program that uses Scraper class to scrape site. I am Using Nokogiri and Open-URI. The error on top is popping up. I looked online and did not find help.
I made sure the site doesn't have typos.
from the CLI class I create a new Scraper class using the site as arg
class KefotoScraper::CLI
attr_accessor :kefoto_scraper
def initialize
site = "https://www.kefotos.mx"
#kefoto_scraper = Scraper.new(site)
end
end
In Scraper I have the following code:
class Scraper
attr_accessor :doc, :product_names, :site, :name, :link
def initialize(site)
#site = site
#doc = doc
#product_names = product_names
#name = name
#link = link
#price_range = [].uniq
scrape_product
end
def get_html
#doc = Nokogiri::HTML(open(#site))
#product_names = doc.css(".navbar-nav li")
product_names
end
def scrape_product
get_html.each {|product|
#name = product.css("span").text
plink = product.css("a").attr("href").text
#link = "#{site}#{link}"
link_doc = Nokogiri::HTML(open(#link))
pr = link_doc.scan(/[\$£](\d{1,3}(,\d{3})*(\.\d*)?)/)
prices = pr_link.text
prices.each {|price|
if #price_range.include?(price[0]) == false
#price_range << price[0]
end
}
new_product = Products.new(#name, #price_range)
puts new_product
}
end
end
I get the following error:
scraper.rb:18:in `initialize': No such file or directory # rb_sysopen - https://www.kefotos.mx (Errno::ENOENT)
open by default operates on local files, not URLs. That error means "I can't find a file on your hard drive named https://www.kefotos.mx".
You can let it work on URIs by requiring the open-uri library:
require 'open-uri'
This will make your code work, but it is a much better practice to use a proper HTTP client to read HTTP resources, as an attacker could potentially use an overloaded open() to access files on your machine's hard drive.
For example, if you were to use just net/http:
# At the top of your scraper.rb:
require 'net/http'
# Then, in your class:
link_doc = Nokogiri::HTML(Net::HTTP.get(URI(#link)))
Trying to establish a connection from a module in Rails and get no connection to server. I have tested the same code outside Rails and it works fine.
require 'rubygems'
require 'net-ldap'
module Foo
module Bar
class User
attr_reader :ldap_connection
def initialize
#ldap = Net::LDAP.new(:host => "<ip-number>", :port => 389)
#treebase = "ou=People, dc=foo, dc=bar"
username = "cn=Manager"
password = "password"
#ldap.auth username, password
begin
if #ldap.bind
#ldap_connection = true
else
#ldap_connection = false
end
rescue Net::LDAP::LdapError
#ldap_connection = false
end
end
end
end
end
Getting Net::LDAP::LdapError: no connection to server exception.
I found a solution/workaround for my problem with auto-loading in Rails. Added a new initializer to ensure that all Ruby files under lib/ get required:
Added config/initializers/require_files_in_lib.rb with this code
Dir[Rails.root + 'lib/**/*.rb'].each do |file|
require file
end
Read more about the workaround: Rails 3 library not loading until require
I'm new to Ruby.
I'm trying to make an app that reads from a serial-port and puts values into a sqlite3 database. When a client connects via TCP socket he should recieve values from the db. Values written by the client should be sent via serial-port.
I have two questions regarding my app.
This would open one connection to the db on the main thread(?) and one for each client..
Is there a better way to use sqlite3?
I think i figured this out. sqlite3 is not thread safe by defaul,t so this seems like the way to do it..
How do i write to the serialport in the recieve_data method? Is it okay to make serial a global variable?
#!/usr/bin/env ruby
#
# server_1
require 'rubygems'
require 'eventmachine'
require 'sqlite3'
require 'em-serialport'
require 'json'
module SocketClient
def self.list
#list ||= []
end
def post_init
SocketClient.list << self
#db = SQLite3::Database.new( "data.db" )
values = []
#db.execute("SELECT * FROM values") do |row|
values << {row[0] => row[1]} #id => value
end
self.send_data "#{values.to_json}\n"
p "Client connected"
end
def unbind
SocketClient.list.delete self
#db.close
end
def receive_data data
p data
#How do i send via serialport from here??? serial.send_data data
end
end
db = SQLite3::Database.new( "data.db" )
EM.run{
EM.start_server '0.0.0.0', 8081, SocketClient
serial = EM.open_serial '/dev/tty.usbserial-xxxxxxxx', 9600, 8, 1, 0
serial.on_data do |data|
#Parse data into an array called values
db.execute("UPDATE values SET value = ? WHERE id = ?", values["value"], values["id"])
SocketClient.list.each{ |c| c.send_data "#{values.to_json}\n" }
end
}
db.close
Setup the constructor for your Socket client so that it will receive the shared serial connection.
module SocketClient
def initialize serial
#serial = serial
end
def receive_data data
p data
#serial.send_data data
end
Then pass it when you call EM.start_server
EM.run{
serial = EM.open_serial '/dev/tty.usbserial-xxxxxxxx', 9600, 8, 1, 0
EM.start_server '0.0.0.0', 8081, SocketClient, serial
I am trying to run the following code to call a webservice from ruby but get an error 'SSL not supported'.
I have httpclient 2.1.5.2 installed.
require 'soap/wsdlDriver'
def validate_certificate(is_ok, ctx)
cert = ctx.current_cert
unless (cert.subject.to_s == cert.issuer.to_s) #check the server certificate only
is_ok &&= File.open(file_name).read == ctx.current_cert.to_pem
end
is_ok
end
def test_webservice
wsdl = "https://.../service.wsdl"
driver = SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver
driver.options['protocol.http.ssl_config.verify_callback'] = method(:validate_certificate)
driver.method(params)
end
could this be your problem?
http://groups.google.com/group/soap4r/browse_thread/thread/e4d87acac8fe51d5
I am writing a ruby script to be used as Postfix SMTP access policy delegation. The script needs to access a Tokyo Tyrant database. I am using EventMachine to take care of network connections. EventMachine needs a EventMachine::Connection class that is instantiated by EventMachine‘s processing loop whenever a new connection is created. so for each connection a class is instantiated and destroyed.
I am creating a connection to Tokyo Tyrant from the post_init of the EventMachine::Connection (ie right after connection is setup) and tearing it down after connection is terminated.
My question is if this is the proper way to connect to db? ie making a connection every yime I need it and tearing it down after I am finished? Wouldn't be better to connect to DB once (when program is started) tear it down during program shutdown? If that is so how should I code that ?
My code is:
require 'rubygems'
require 'eventmachine'
require 'rufus/tokyo/tyrant'
class LineCounter < EM::Connection
ActionAllow = "action=dunno\n\n"
def post_init
puts "Received a new connection"
#tokyo = Rufus::Tokyo::Tyrant.new('server', 1978)
#data_received = ""
end
def receive_data data
#data_received << data
#data_received.lines do |line|
key = line.split('=')[0]
value = line.split('=')[1]
#reverse_client_name = value.strip() if key == 'reverse_client_name'
#client_address = value.strip() if key == 'client_address'
#tokyo[#client_address] = #reverse_client_name
end
puts #client_address, #reverse_client_name
send_data ActionAllow
end
def unbind
#tokyo.close
end
end
EventMachine::run {
host,port = "127.0.0.1", 9997
EventMachine::start_server host, port, LineCounter
puts "Now accepting connections on address #{host}, port #{port}..."
EventMachine::add_periodic_timer( 10 ) { $stderr.write "*" }
}
with regards,
raj
Surprising there's no answers to this question.
What you probably need is a connection pool where you can fetch, use, and return connections as they are required.
class ConnectionPool
def initialize(&block)
#pool = [ ]
#generator = block
end
def fetch
#pool.shift or #generator and #generator.call
end
def release(handle)
#pool.push(handle)
end
def use
if (block_given?)
handle = fetch
yield(handle)
release(handle)
end
end
end
# Declare a pool with an appropriate connection generator
tokyo_pool = ConnectionPool.new do
Rufus::Tokyo::Tyrant.new('server', 1978)
end
# Fetch/Release cycle
tokyo = tokyo_pool.fetch
tokyo[#client_address] = #reverse_client_name
tokyo_pool.release(tokyo)
# Simple block-method for use
tokyo_pool.use do |tokyo|
tokyo[#client_address] = #reverse_client_name
end