如何在rails应用程序中捕获命令行/linux命令并将输出存储在变量中



在rails代码中,我有以下代码需要在rails应用程序中执行。通常,您会在命令行上运行此操作。她是定义的代码:

COMMAND=->(url, port){%x"echo QUIT | openssl s_client -CApath /etc/ssl/certs/ -quiet -no_ign_eof -servername #{url} -verify_hostname #{url} -connect #{url}:#{port}"}

在应用程序中,我需要执行以下操作:

Model::COMMAND.call('website.com',443)

该命令的"官方"输出是一个空字符串。然而,我看到了以下内容:

[53] pry(main)> SiteCheck::COMMAND.call('website.com',443)
depth=0 C = US, ST = States, L = Somewhere, O =Corp, serialNumber = 123456789, CN = www.website.com, postalCode = 12345, businessCategory = Private Organization, street = JFK Random Street, jurisdictionST = Nevada, jurisdictionC = US
verify error:num=62:Hostname mismatch
verify return:1
depth=3 C = PL, O = Unizeto Technologies S.A., OU = Certum Certification Authority, CN = Certum Trusted Network CA
verify return:1
depth=2 C = US, ST = States, L = Somewhere, O = Corporation, CN = EV Root Certification Authority RSA R2
verify return:1
depth=1 C = US, ST = States, L = Somewhere, O = Corp, CN = EV SSL Intermediate CA RSA R3
verify return:1
depth=0 C = US, ST = States, L = Somewhere, O = Corp, serialNumber = 123456789, CN = www.website.com, postalCode = 12345, businessCategory = Private Organization, street = JFK Random Street, jurisdictionST = Nevada, jurisdictionC = US
verify return:1
DONE
=> ""

我特别需要的是verify error: num=62 Hostname mismatch部分。我该如何捕捉?我试着使用pop3,但我的问题是返回值是一个空字符串,所以在某种程度上,我得到了一个返回的结果,只是不是我想要的。有没有办法用ruby来捕捉它?

该输出将进入stderr。您可以使用Open3.capture3:

require 'open3'
stdin, stderr = Open3.capture3(
"openssl s_client -CApath /etc/ssl/certs/ -quiet -no_ign_eof -servername #{url} -verify_hostname #{url} -connect #{url}:#{port}",
stdin_data:'QUIT'
)

此外,您可以尝试从ruby本身启动该连接,而不是生成一个进程:

require 'openssl'
require 'socket'
def ssl_connect_verify(host, port)
context = OpenSSL::SSL::SSLContext.new
context.ca_file = '/usr/local/etc/openssl@1.1/cert.pem' # this is for mac, your path may differ
context.verify_mode = OpenSSL::SSL::VERIFY_PEER
tcp_client = TCPSocket.new host, port
ssl_client = OpenSSL::SSL::SSLSocket.new(tcp_client, context)
ssl_client.hostname = host # SNI
ssl_client.connect
if (san_ext = ssl_client.peer_cert.extensions.select{|e| e.oid == 'subjectAltName' }.first)
dns_names = san_ext.value.split(/,s*/).map{|s| s.delete_prefix "DNS:"}
unless dns_names.any?{|san| OpenSSL::SSL.verify_hostname(host, san)}
raise "Cannot verify hostname..."
end
end
ssl_client.peer_cert_chain.map{|cert|
# cert is a OpenSSL::X509::Certificate, see documentation on its fields
cert.subject.to_s
}
rescue OpenSSL::SSL::SSLError => e
# check for error message etc.
puts "Cannot connect: #{e.to_s}"
return []
ensure
ssl_client.close
end

puts ssl_connect_verify('google.com', 443).join("n")

最新更新