diff options
author | Florian Wininger <florian@cyberwatch.fr> | 2021-07-01 22:27:11 +0200 |
---|---|---|
committer | Florian Wininger <florian@cyberwatch.fr> | 2021-07-01 22:27:11 +0200 |
commit | da80a1f606f6985ed579126c22682ed0ce044c21 (patch) | |
tree | 0084b6bcc50c0542abc9c0e9fb33937d52880f22 | |
parent | a20286be502eaf8e44309ecffe0cc5b9e0e9ee88 (diff) | |
download | net-ssh-da80a1f606f6985ed579126c22682ed0ce044c21.tar.gz |
Remove Trailing white space
58 files changed, 723 insertions, 773 deletions
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index e0d5c2e..30bb007 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -77,12 +77,6 @@ Layout/SpaceInsideReferenceBrackets: Exclude: - 'lib/net/ssh/transport/algorithms.rb' -# Offense count: 732 -# Cop supports --auto-correct. -# Configuration parameters: AllowInHeredoc. -Layout/TrailingWhitespace: - Enabled: false - # Offense count: 4 # Configuration parameters: AllowSafeAssignment. Lint/AssignmentInCondition: diff --git a/lib/net/ssh/authentication/agent.rb b/lib/net/ssh/authentication/agent.rb index 7ff0096..f521e55 100644 --- a/lib/net/ssh/authentication/agent.rb +++ b/lib/net/ssh/authentication/agent.rb @@ -198,13 +198,13 @@ module Net type, = send_and_wait(SSH2_AGENT_LOCK, :string, password) raise AgentError, "could not lock agent" if type != SSH_AGENT_SUCCESS end - + # unlock the ssh agent with password def unlock(password) type, = send_and_wait(SSH2_AGENT_UNLOCK, :string, password) raise AgentError, "could not unlock agent" if type != SSH_AGENT_SUCCESS end - + private def unix_socket_class diff --git a/lib/net/ssh/authentication/certificate.rb b/lib/net/ssh/authentication/certificate.rb index 28fbe71..deeb71d 100644 --- a/lib/net/ssh/authentication/certificate.rb +++ b/lib/net/ssh/authentication/certificate.rb @@ -31,7 +31,7 @@ module Net cert.key_id = buffer.read_string cert.valid_principals = buffer.read_buffer.read_all(&:read_string) cert.valid_after = Time.at(buffer.read_int64) - + cert.valid_before = if RUBY_PLATFORM == "java" # 0x20c49ba5e353f7 = 0x7fffffffffffffff/1000, the largest value possible for JRuby # JRuby Time.at multiplies the arg by 1000, and then stores it in a signed long. diff --git a/lib/net/ssh/authentication/ed25519_loader.rb b/lib/net/ssh/authentication/ed25519_loader.rb index 08ccd94..94f87aa 100644 --- a/lib/net/ssh/authentication/ed25519_loader.rb +++ b/lib/net/ssh/authentication/ed25519_loader.rb @@ -1,10 +1,9 @@ -module Net - module SSH +module Net + module SSH module Authentication # Loads ED25519 support which requires optinal dependecies like # ed25519, bcrypt_pbkdf module ED25519Loader - begin require 'net/ssh/authentication/ed25519' LOADED = true @@ -13,20 +12,19 @@ module Net ERROR = e LOADED = false end - + def self.raiseUnlessLoaded(message) description = ERROR.is_a?(LoadError) ? dependenciesRequiredForED25519 : '' description << "#{ERROR.class} : \"#{ERROR.message}\"\n" if ERROR raise NotImplementedError, "#{message}\n#{description}" unless LOADED end - + def self.dependenciesRequiredForED25519 result = "net-ssh requires the following gems for ed25519 support:\n" result << " * ed25519 (>= 1.2, < 2.0)\n" result << " * bcrypt_pbkdf (>= 1.0, < 2.0)\n" unless RUBY_PLATFORM == "java" result << "See https://github.com/net-ssh/net-ssh/issues/565 for more information\n" end - end end end diff --git a/lib/net/ssh/authentication/methods/none.rb b/lib/net/ssh/authentication/methods/none.rb index c1184e1..09fdac8 100644 --- a/lib/net/ssh/authentication/methods/none.rb +++ b/lib/net/ssh/authentication/methods/none.rb @@ -9,24 +9,23 @@ module Net class None < Abstract # Attempt to authenticate as "none" def authenticate(next_service, user="", password="") - send_message(userauth_request(user, next_service, "none")) + send_message(userauth_request(user, next_service, "none")) message = session.next_message - + case message.type when USERAUTH_SUCCESS debug { "none succeeded" } return true when USERAUTH_FAILURE debug { "none failed" } - + raise Net::SSH::Authentication::DisallowedMethod unless message[:authentications].split(/,/).include? 'none' - + return false else raise Net::SSH::Exception, "unexpected reply to USERAUTH_REQUEST: #{message.type} (#{message.inspect})" - end - + end end end end diff --git a/lib/net/ssh/authentication/pageant.rb b/lib/net/ssh/authentication/pageant.rb index f3de568..9c44c19 100644 --- a/lib/net/ssh/authentication/pageant.rb +++ b/lib/net/ssh/authentication/pageant.rb @@ -21,8 +21,8 @@ end require 'net/ssh/errors' -module Net - module SSH +module Net + module SSH module Authentication # This module encapsulates the implementation of a socket factory that # uses the PuTTY "pageant" utility to obtain information about SSH @@ -32,28 +32,27 @@ module Net # by Guillaume Marçais (guillaume.marcais@free.fr). It is used and # relicensed by permission. module Pageant - # From Putty pageant.c AGENT_MAX_MSGLEN = 8192 AGENT_COPYDATA_ID = 0x804e50ba - + # The definition of the Windows methods and data structures used in # communicating with the pageant process. module Win # rubocop:disable Metrics/ModuleLength # Compatibility on initialization if RUBY_VERSION < "1.9" extend DL::Importable - + dlload 'user32.dll' dlload 'kernel32.dll' dlload 'advapi32.dll' - + SIZEOF_DWORD = DL.sizeof('L') elsif RUBY_VERSION < "2.1" extend DL::Importer dlload 'user32.dll','kernel32.dll', 'advapi32.dll' include DL::Win32Types - + SIZEOF_DWORD = DL::SIZEOF_LONG else extend Fiddle::Importer @@ -61,7 +60,7 @@ module Net include Fiddle::Win32Types SIZEOF_DWORD = Fiddle::SIZEOF_LONG end - + if RUBY_ENGINE == "jruby" typealias("HANDLE", "void *") # From winnt.h typealias("PHANDLE", "void *") # From winnt.h @@ -75,105 +74,105 @@ module Net typealias("LPARAM", "long *") # From windef.h typealias("PDWORD_PTR", "long *") # From basetsd.h typealias("USHORT", "unsigned short") # From windef.h - + # From winbase.h, winnt.h INVALID_HANDLE_VALUE = -1 NULL = nil PAGE_READWRITE = 0x0004 FILE_MAP_WRITE = 2 WM_COPYDATA = 74 - + SMTO_NORMAL = 0 # From winuser.h - + SUFFIX = if RUBY_ENGINE == "jruby" "A" else "" end - + # args: lpClassName, lpWindowName extern "HWND FindWindow#{SUFFIX}(LPCTSTR, LPCTSTR)" - + # args: none extern 'DWORD GetCurrentThreadId()' - + # args: hFile, (ignored), flProtect, dwMaximumSizeHigh, # dwMaximumSizeLow, lpName extern "HANDLE CreateFileMapping#{SUFFIX}(HANDLE, void *, DWORD, " + "DWORD, DWORD, LPCTSTR)" - + # args: hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh, # dwfileOffsetLow, dwNumberOfBytesToMap extern 'LPVOID MapViewOfFile(HANDLE, DWORD, DWORD, DWORD, DWORD)' - + # args: lpBaseAddress extern 'BOOL UnmapViewOfFile(LPCVOID)' - + # args: hObject extern 'BOOL CloseHandle(HANDLE)' - + # args: hWnd, Msg, wParam, lParam, fuFlags, uTimeout, lpdwResult extern "LRESULT SendMessageTimeout#{SUFFIX}(HWND, UINT, WPARAM, LPARAM, " + "UINT, UINT, PDWORD_PTR)" - + # args: none extern 'DWORD GetLastError()' - + # args: none extern 'HANDLE GetCurrentProcess()' - + # args: hProcessHandle, dwDesiredAccess, (out) phNewTokenHandle extern 'BOOL OpenProcessToken(HANDLE, DWORD, PHANDLE)' - + # args: hTokenHandle, uTokenInformationClass, # (out) lpTokenInformation, dwTokenInformationLength # (out) pdwInfoReturnLength extern 'BOOL GetTokenInformation(HANDLE, UINT, LPVOID, DWORD, ' + 'PDWORD)' - + # args: (out) lpSecurityDescriptor, dwRevisionLevel extern 'BOOL InitializeSecurityDescriptor(LPVOID, DWORD)' - + # args: (out) lpSecurityDescriptor, lpOwnerSid, bOwnerDefaulted extern 'BOOL SetSecurityDescriptorOwner(LPVOID, LPVOID, BOOL)' - + # args: pSecurityDescriptor extern 'BOOL IsValidSecurityDescriptor(LPVOID)' - + # Constants needed for security attribute retrieval. # Specifies the access mask corresponding to the desired access # rights. TOKEN_QUERY = 0x8 - + # The value of TOKEN_USER from the TOKEN_INFORMATION_CLASS enum. TOKEN_USER_INFORMATION_CLASS = 1 - + # The initial revision level assigned to the security descriptor. REVISION = 1 - + # Structs for security attribute functions. # Holds the retrieved user access token. TOKEN_USER = struct ['void * SID', 'DWORD ATTRIBUTES'] - + # Contains the security descriptor, this gets passed to the # function that constructs the shared memory map. SECURITY_ATTRIBUTES = struct ['DWORD nLength', 'LPVOID lpSecurityDescriptor', 'BOOL bInheritHandle'] - + # The security descriptor holds security information. SECURITY_DESCRIPTOR = struct ['UCHAR Revision', 'UCHAR Sbz1', 'USHORT Control', 'LPVOID Owner', 'LPVOID Group', 'LPVOID Sacl', 'LPVOID Dacl'] - + # The COPYDATASTRUCT is used to send WM_COPYDATA messages COPYDATASTRUCT = if RUBY_ENGINE == "jruby" struct ['ULONG_PTR dwData', 'DWORD cbData', 'LPVOID lpData'] else struct ['uintptr_t dwData', 'DWORD cbData', 'LPVOID lpData'] end - + # Compatibility for security attribute retrieval. if RUBY_VERSION < "1.9" # Alias functions to > 1.9 capitalization @@ -195,15 +194,15 @@ module Net alias_method new_name, name module_function new_name end - + def self.malloc_ptr(size) return DL.malloc(size) end - + def self.get_ptr(data) return data.to_ptr end - + def self.set_ptr_data(ptr, data) ptr[0] = data end @@ -219,15 +218,15 @@ module Net attach_function :malloc, [:size_t], :pointer attach_function :free, [:pointer], :void end - + def self.malloc_ptr(size) Fiddle::Pointer.new(LibC.malloc(size), size, LibC.method(:free)) end - + def self.get_ptr(ptr) return data.address end - + def self.set_ptr_data(ptr, data) ptr.write_string_length(data, data.size) end @@ -235,19 +234,19 @@ module Net def self.malloc_ptr(size) return DL::CPtr.malloc(size, DL::RUBY_FREE) end - + def self.get_ptr(data) return DL::CPtr.to_ptr data end - + def self.set_ptr_data(ptr, data) DL::CPtr.new(ptr)[0,data.size] = data end end - + def self.get_security_attributes_for_user user = get_current_user - + psd_information = malloc_ptr(Win::SECURITY_DESCRIPTOR.size) raise_error_if_zero( Win.InitializeSecurityDescriptor(psd_information, @@ -260,26 +259,26 @@ module Net raise_error_if_zero( Win.IsValidSecurityDescriptor(psd_information) ) - + sa = Win::SECURITY_ATTRIBUTES.new(to_struct_ptr(malloc_ptr(Win::SECURITY_ATTRIBUTES.size))) sa.nLength = Win::SECURITY_ATTRIBUTES.size sa.lpSecurityDescriptor = psd_information.to_i sa.bInheritHandle = 1 - + return sa end - + if RUBY_ENGINE == "jruby" def self.ptr_to_s(ptr, size) ret = ptr.to_s(size) ret << "\x00" while ret.size < size ret end - + def self.ptr_to_handle(phandle) phandle.ptr end - + def self.ptr_to_dword(ptr) first = ptr.ptr.to_i second = ptr_to_s(ptr,Win::SIZEOF_DWORD).unpack('L')[0] @@ -287,19 +286,19 @@ module Net first end - + def self.to_token_user(ptoken_information) TOKEN_USER.new(ptoken_information.to_ptr) end - + def self.to_struct_ptr(ptr) ptr.to_ptr end - + def self.get_sid(user) ptr_to_s(user.to_ptr.ptr,Win::SIZEOF_DWORD).unpack('L')[0] end - + def self.get_sid_ptr(user) user.to_ptr.ptr end @@ -307,28 +306,28 @@ module Net def self.get_sid(user) user.SID end - + def self.ptr_to_handle(phandle) phandle.ptr.to_i end - + def self.to_struct_ptr(ptr) ptr end - + def self.ptr_to_dword(ptr) ptr.to_s(Win::SIZEOF_DWORD).unpack('L')[0] end - + def self.to_token_user(ptoken_information) TOKEN_USER.new(ptoken_information) end - + def self.get_sid_ptr(user) user.SID end end - + def self.get_current_user token_handle = open_process_token(Win.GetCurrentProcess, Win::TOKEN_QUERY) @@ -336,10 +335,10 @@ module Net Win::TOKEN_USER_INFORMATION_CLASS) return token_user end - + def self.open_process_token(process_handle, desired_access) ptoken_handle = malloc_ptr(Win::SIZEOF_DWORD) - + raise_error_if_zero( Win.OpenProcessToken(process_handle, desired_access, ptoken_handle) @@ -347,12 +346,12 @@ module Net token_handle = ptr_to_handle(ptoken_handle) return token_handle end - + def self.get_token_information(token_handle, token_information_class) # Hold the size of the information to be returned preturn_length = malloc_ptr(Win::SIZEOF_DWORD) - + # Going to throw an INSUFFICIENT_BUFFER_ERROR, but that is ok # here. This is retrieving the size of the information to be # returned. @@ -360,7 +359,7 @@ module Net token_information_class, Win::NULL, 0, preturn_length) ptoken_information = malloc_ptr(ptr_to_dword(preturn_length)) - + # This call is going to write the requested information to # the memory location referenced by token_information. raise_error_if_zero( @@ -370,76 +369,76 @@ module Net ptoken_information.size, preturn_length) ) - + return to_token_user(ptoken_information) end - + def self.raise_error_if_zero(result) if result == 0 raise "Windows error: #{Win.GetLastError}" end end - + # Get a null-terminated string given a string. def self.get_cstr(str) return str + "\000" end end - + # This is the pseudo-socket implementation that mimics the interface of # a socket, translating each request into a Windows messaging call to # the pageant daemon. This allows pageant support to be implemented # simply by replacing the socket factory used by the Agent class. class Socket private_class_method :new - + # The factory method for creating a new Socket instance. def self.open new end - + # Create a new instance that communicates with the running pageant # instance. If no such instance is running, this will cause an error. def initialize @win = Win.FindWindow("Pageant", "Pageant") - + if @win.to_i == 0 raise Net::SSH::Exception, "pageant process not running" end - + @input_buffer = Net::SSH::Buffer.new @output_buffer = Net::SSH::Buffer.new end - + # Forwards the data to #send_query, ignoring any arguments after # the first. def send(data, *args) @input_buffer.append(data) - + ret = data.length - + while true return ret if @input_buffer.length < 4 msg_length = @input_buffer.read_long + 4 @input_buffer.reset! - + return ret if @input_buffer.length < msg_length msg = @input_buffer.read!(msg_length) @output_buffer.append(send_query(msg)) end end - + # Reads +n+ bytes from the cached result of the last query. If +n+ # is +nil+, returns all remaining data from the last query. def read(n = nil) @output_buffer.read(n) end - + def close; end - + # Packages the given query string and sends it to the pageant # process via the Windows messaging subsystem. The result is # cached, to be returned piece-wise when #read is called. @@ -448,29 +447,29 @@ module Net filemap = 0 ptr = nil id = Win.malloc_ptr(Win::SIZEOF_DWORD) - + mapname = "PageantRequest%08x" % Win.GetCurrentThreadId() security_attributes = Win.get_ptr Win.get_security_attributes_for_user - + filemap = Win.CreateFileMapping(Win::INVALID_HANDLE_VALUE, security_attributes, Win::PAGE_READWRITE, 0, AGENT_MAX_MSGLEN, mapname) - + if filemap == 0 || filemap == Win::INVALID_HANDLE_VALUE raise Net::SSH::Exception, "Creation of file mapping failed with error: #{Win.GetLastError}" end - + ptr = Win.MapViewOfFile(filemap, Win::FILE_MAP_WRITE, 0, 0, 0) - + if ptr.nil? || ptr.null? raise Net::SSH::Exception, "Mapping of file failed" end - + Win.set_ptr_data(ptr, query) - + # using struct to achieve proper alignment and field size on 64-bit platform cds = Win::COPYDATASTRUCT.new(Win.malloc_ptr(Win::COPYDATASTRUCT.size)) cds.dwData = AGENT_COPYDATA_ID @@ -478,14 +477,14 @@ module Net cds.lpData = Win.get_cstr(mapname) succ = Win.SendMessageTimeout(@win, Win::WM_COPYDATA, Win::NULL, cds.to_ptr, Win::SMTO_NORMAL, 5000, id) - + if succ > 0 retlen = 4 + ptr.to_s(4).unpack("N")[0] res = ptr.to_s(retlen) else raise Net::SSH::Exception, "Message failed with error: #{Win.GetLastError}" end - + return res ensure Win.UnmapViewOfFile(ptr) unless ptr.nil? || ptr.null? diff --git a/lib/net/ssh/buffered_io.rb b/lib/net/ssh/buffered_io.rb index d974a1d..464ba4c 100644 --- a/lib/net/ssh/buffered_io.rb +++ b/lib/net/ssh/buffered_io.rb @@ -1,7 +1,7 @@ require 'net/ssh/buffer' require 'net/ssh/loggable' -module Net +module Net module SSH # This module is used to extend sockets and other IO objects, to allow # them to be buffered for both read and write. This abstraction makes it @@ -47,7 +47,7 @@ module Net # end module BufferedIo include Loggable - + # Called when the #extend is called on an object, with this module as the # argument. It ensures that the modules instance variables are all properly # initialized. @@ -55,7 +55,7 @@ module Net # need to use __send__ because #send is overridden in Socket object.__send__(:initialize_buffered_io) end - + # Tries to read up to +n+ bytes of data from the remote end, and appends # the data to the input buffer. It returns the number of bytes read, or 0 # if no data was available to be read. @@ -69,31 +69,31 @@ module Net @input_errors << e return 0 end - + # Read up to +length+ bytes from the input buffer. If +length+ is nil, # all available data is read from the buffer. (See #available.) def read_available(length=nil) input.read(length || available) end - + # Returns the number of bytes available to be read from the input buffer. # (See #read_available.) def available input.available end - + # Enqueues data in the output buffer, to be written when #send_pending # is called. Note that the data is _not_ sent immediately by this method! def enqueue(data) output.append(data) end - + # Returns +true+ if there is data waiting in the output buffer, and # +false+ otherwise. def pending_write? output.length > 0 end - + # Sends as much of the pending output as possible. Returns +true+ if any # data was sent, and +false+ otherwise. def send_pending @@ -106,7 +106,7 @@ module Net return false end end - + # Calls #send_pending repeatedly, if necessary, blocking until the output # buffer is empty. def wait_for_pending_sends @@ -118,28 +118,28 @@ module Net send_pending end end - + public # these methods are primarily for use in tests - + def write_buffer #:nodoc: output.to_s end - + def read_buffer #:nodoc: input.to_s end - + private - + #-- # Can't use attr_reader here (after +private+) without incurring the # wrath of "ruby -w". We hates it. #++ - + def input; @input; end def output; @output; end - + # Initializes the intput and output buffers for this object. This method # is called automatically when the module is mixed into an object via # Object#extend (see Net::SSH::BufferedIo.extended), but must be called @@ -181,7 +181,7 @@ module Net end end end - + def send_pending begin super diff --git a/lib/net/ssh/connection/channel.rb b/lib/net/ssh/connection/channel.rb index 835d72f..b169679 100644 --- a/lib/net/ssh/connection/channel.rb +++ b/lib/net/ssh/connection/channel.rb @@ -54,55 +54,55 @@ module Net class Channel include Loggable include Constants - + # The local id for this channel, assigned by the Net::SSH::Connection::Session instance. attr_reader :local_id - + # The remote id for this channel, assigned by the remote host. attr_reader :remote_id - + # The type of this channel, usually "session". attr_reader :type - + # The underlying Net::SSH::Connection::Session instance that supports this channel. attr_reader :connection - + # The maximum packet size that the local host can receive. attr_reader :local_maximum_packet_size - + # The maximum amount of data that the local end of this channel can # receive. This is a total, not per-packet. attr_reader :local_maximum_window_size - + # The maximum packet size that the remote host can receive. attr_reader :remote_maximum_packet_size - + # The maximum amount of data that the remote end of this channel can # receive. This is a total, not per-packet. attr_reader :remote_maximum_window_size - + # This is the remaining window size on the local end of this channel. When # this reaches zero, no more data can be received. attr_reader :local_window_size - + # This is the remaining window size on the remote end of this channel. When # this reaches zero, no more data can be sent. attr_reader :remote_window_size - + # A hash of properties for this channel. These can be used to store state # information about this channel. See also #[] and #[]=. attr_reader :properties - + # The output buffer for this channel. Data written to the channel is # enqueued here, to be written as CHANNEL_DATA packets during each pass of # the event loop. See Connection::Session#process and #enqueue_pending_output. attr_reader :output #:nodoc: - + # The list of pending requests. Each time a request is sent which requires # a reply, the corresponding callback is pushed onto this queue. As responses # arrive, they are shifted off the front and handled. attr_reader :pending_requests #:nodoc: - + # Instantiates a new channel on the given connection, of the given type, # and with the given id. If a block is given, it will be remembered until # the channel is confirmed open by the server, and will be invoked at @@ -111,36 +111,36 @@ module Net # This also sets the default maximum packet size and maximum window size. def initialize(connection, type, local_id, max_pkt_size = 0x8000, max_win_size = 0x20000, &on_confirm_open) self.logger = connection.logger - + @connection = connection @type = type @local_id = local_id - + @local_maximum_packet_size = max_pkt_size @local_window_size = @local_maximum_window_size = max_win_size - + @on_confirm_open = on_confirm_open - + @output = Buffer.new - + @properties = {} - + @pending_requests = [] @on_open_failed = @on_data = @on_extended_data = @on_process = @on_close = @on_eof = nil @on_request = {} @closing = @eof = @sent_eof = @local_closed = @remote_closed = false end - + # A shortcut for accessing properties of the channel (see #properties). def [](name) @properties[name] end - + # A shortcut for setting properties of the channel (see #properties). def []=(name, value) @properties[name] = value end - + # Syntactic sugar for executing a command. Sends a channel request asking # that the given command be invoked. If the block is given, it will be # called when the server responds. The first parameter will be the @@ -160,7 +160,7 @@ module Net def exec(command, &block) send_channel_request("exec", :string, command, &block) end - + # Syntactic sugar for requesting that a subsystem be started. Subsystems # are a way for other protocols (like SFTP) to be run, using SSH as # the transport. Generally, you'll never need to call this directly unless @@ -177,7 +177,7 @@ module Net def subsystem(subsystem, &block) send_channel_request("subsystem", :string, subsystem, &block) end - + # Syntactic sugar for setting an environment variable in the remote # process' environment. Note that for security reasons, the server may # refuse to set certain environment variables, or all, at the server's @@ -189,7 +189,7 @@ module Net def env(variable_name, variable_value, &block) send_channel_request("env", :string, variable_name, :string, variable_value, &block) end - + # A hash of the valid PTY options (see #request_pty). VALID_PTY_OPTIONS = { term: "xterm", chars_wide: 80, @@ -197,7 +197,7 @@ module Net pixels_wide: 640, pixels_high: 480, modes: {} } - + # Requests that a pseudo-tty (or "pty") be made available for this channel. # This is useful when you want to invoke and interact with some kind of # screen-based program (e.g., vim, or some menuing system). @@ -220,21 +220,21 @@ module Net def request_pty(opts={}, &block) extra = opts.keys - VALID_PTY_OPTIONS.keys raise ArgumentError, "invalid option(s) to request_pty: #{extra.inspect}" if extra.any? - + opts = VALID_PTY_OPTIONS.merge(opts) - + modes = opts[:modes].inject(Buffer.new) do |memo, (mode, data)| memo.write_byte(mode).write_long(data) end # mark the end of the mode opcode list with a 0 byte modes.write_byte(0) - + send_channel_request("pty-req", :string, opts[:term], :long, opts[:chars_wide], :long, opts[:chars_high], :long, opts[:pixels_wide], :long, opts[:pixels_high], :string, modes.to_s, &block) end - + # Sends data to the channel's remote endpoint. This usually has the # effect of sending the given string to the remote process' stdin stream. # Note that it does not immediately send the data across the channel, @@ -253,7 +253,7 @@ module Net output.append(data.to_s) end - + # Returns true if the channel exists in the channel list of the session, # and false otherwise. This can be used to determine whether a channel has # been closed or not. @@ -262,7 +262,7 @@ module Net def active? connection.channels.key?(local_id) end - + # Runs the SSH event loop until the channel is no longer active. This is # handy for blocking while you wait for some channel to finish. # @@ -271,7 +271,7 @@ module Net def wait connection.loop { active? } end - + # True if close() has been called; NOTE: if the channel has data waiting to # be sent then the channel will close after all the data is sent. See # closed?() to determine if we have actually sent CHANNEL_CLOSE to server. @@ -280,20 +280,20 @@ module Net def closing? @closing end - + # True if we have sent CHANNEL_CLOSE to the remote server. def local_closed? @local_closed end - + def remote_closed? @remote_closed end - + def remote_closed! @remote_closed = true end - + # Requests that the channel be closed. It only marks the channel to be closed # the CHANNEL_CLOSE message will be sent from event loop def close @@ -301,14 +301,14 @@ module Net @closing = true end - + # Returns true if the local end of the channel has declared that no more # data is forthcoming (see #eof!). Trying to send data via #send_data when # this is true will result in an exception being raised. def eof? @eof end - + # Tells the remote end of the channel that no more data is forthcoming # from this end of the channel. The remote end may still send data. # The CHANNEL_EOF packet will be sent once the output buffer is empty. @@ -317,26 +317,26 @@ module Net @eof = true end - + # If an #on_process handler has been set up, this will cause it to be # invoked (passing the channel itself as an argument). It also causes all # pending output to be enqueued as CHANNEL_DATA packets (see #enqueue_pending_output). def process @on_process.call(self) if @on_process enqueue_pending_output - + if @eof and not @sent_eof and output.empty? and remote_id and not @local_closed connection.send_message(Buffer.from(:byte, CHANNEL_EOF, :long, remote_id)) @sent_eof = true end - + if @closing and not @local_closed and output.empty? and remote_id connection.send_message(Buffer.from(:byte, CHANNEL_CLOSE, :long, remote_id)) @local_closed = true connection.cleanup_channel(self) end end - + # Registers a callback to be invoked when data packets are received by the # channel. The callback is called with the channel as the first argument, # and the data as the second. @@ -351,7 +351,7 @@ module Net old, @on_data = @on_data, block old end - + # Registers a callback to be invoked when extended data packets are received # by the channel. The callback is called with the channel as the first # argument, the data type (as an integer) as the second, and the data as @@ -366,7 +366,7 @@ module Net old, @on_extended_data = @on_extended_data, block old end - + # Registers a callback to be invoked for each pass of the event loop for # this channel. There are no guarantees on timeliness in the event loop, # but it will be called roughly once for each packet received by the @@ -393,7 +393,7 @@ module Net old, @on_process = @on_process, block old end - + # Registers a callback to be invoked when the server acknowledges that a # channel is closed. This is invoked with the channel as the sole argument. # @@ -404,7 +404,7 @@ module Net old, @on_close = @on_close, block old end - + # Registers a callback to be invoked when the server indicates that no more # data will be sent to the channel (although the channel can still send # data to the server). The channel is the sole argument to the callback. @@ -416,7 +416,7 @@ module Net old, @on_eof = @on_eof, block old end - + # Registers a callback to be invoked when the server was unable to open # the requested channel. The channel itself will be passed to the block, # along with the integer "reason code" for the failure, and a textual @@ -431,7 +431,7 @@ module Net old, @on_open_failed = @on_open_failed, block old end - + # Registers a callback to be invoked when a channel request of the given # type is received. The callback will receive the channel as the first # argument, and the associated (unparsed) data as the second. The data @@ -462,7 +462,7 @@ module Net old, @on_request[type] = @on_request[type], block old end - + # Sends a new channel request with the given name. The extra +data+ # parameter must either be empty, or consist of an even number of # arguments. See Net::SSH::Buffer.from for a description of their format. @@ -495,9 +495,9 @@ module Net connection.send_message(msg) pending_requests << callback if callback end - + public # these methods are public, but for Net::SSH internal use only - + # Enqueues pending output at the connection as CHANNEL_DATA packets. This # does nothing if the channel has not yet been confirmed open (see # #do_open_confirmation). This is called automatically by #process, which @@ -505,12 +505,12 @@ module Net # generally not need to invoke it directly. def enqueue_pending_output #:nodoc: return unless remote_id - + while output.length > 0 length = output.length length = remote_window_size if length > remote_window_size length = remote_maximum_packet_size if length > remote_maximum_packet_size - + if length > 0 connection.send_message(Buffer.from(:byte, CHANNEL_DATA, :long, remote_id, :string, output.read(length))) output.consume! @@ -520,7 +520,7 @@ module Net end end end - + # Invoked when the server confirms that a channel has been opened. # The remote_id is the id of the channel as assigned by the remote host, # and max_window and max_packet are the maximum window and maximum @@ -536,7 +536,7 @@ module Net set_remote_env(connection.options[:set_env]) if connection.options[:set_env] @on_confirm_open.call(self) if @on_confirm_open end - + # Invoked when the server failed to open the channel. If an #on_open_failed # callback was specified, it will be invoked with the channel, reason code, # and description as arguments. Otherwise, a ChannelOpenFailed exception @@ -548,7 +548,7 @@ module Net raise ChannelOpenFailed.new(reason_code, description) end end - + # Invoked when the server sends a CHANNEL_WINDOW_ADJUST packet, and # causes the remote window size to be adjusted upwards by the given # number of bytes. This has the effect of allowing more data to be sent @@ -557,7 +557,7 @@ module Net @remote_maximum_window_size += bytes @remote_window_size += bytes end - + # Invoked when the server sends a channel request. If any #on_request # callback has been registered for the specific type of this request, # it is invoked. If +want_reply+ is true, a packet will be sent of @@ -568,20 +568,20 @@ module Net # request-specific data as the second. def do_request(request, want_reply, data) #:nodoc: result = true - + begin callback = @on_request[request] or raise ChannelRequestFailed callback.call(self, data) rescue ChannelRequestFailed result = false end - + if want_reply msg = Buffer.from(:byte, result ? CHANNEL_SUCCESS : CHANNEL_FAILURE, :long, remote_id) connection.send_message(msg) end end - + # Invokes the #on_data callback when the server sends data to the # channel. This will reduce the available window size on the local end, # but does not actually throttle requests that come in illegally when @@ -591,7 +591,7 @@ module Net update_local_window_size(data.length) @on_data.call(self, data) if @on_data end - + # Invokes the #on_extended_data callback when the server sends # extended data to the channel. This will reduce the available window # size on the local end. The callback is invoked with the channel, @@ -600,20 +600,20 @@ module Net update_local_window_size(data.length) @on_extended_data.call(self, type, data) if @on_extended_data end - + # Invokes the #on_eof callback when the server indicates that no # further data is forthcoming. The callback is invoked with the channel # as the argument. def do_eof @on_eof.call(self) if @on_eof end - + # Invokes the #on_close callback when the server closes a channel. # The channel is the only argument. def do_close @on_close.call(self) if @on_close end - + # Invokes the next pending request callback with +false+ as the second # argument. def do_failure @@ -623,7 +623,7 @@ module Net error { "channel failure received with no pending request to handle it (bug?)" } end end - + # Invokes the next pending request callback with +true+ as the second # argument. def do_success diff --git a/lib/net/ssh/connection/event_loop.rb b/lib/net/ssh/connection/event_loop.rb index 56085cf..869e38f 100644 --- a/lib/net/ssh/connection/event_loop.rb +++ b/lib/net/ssh/connection/event_loop.rb @@ -1,7 +1,7 @@ require 'net/ssh/loggable' -module Net - module SSH +module Net + module SSH module Connection # EventLoop can be shared across multiple sessions # @@ -11,25 +11,25 @@ module Net # and we don't pass session. class EventLoop include Loggable - + def initialize(logger=nil) self.logger = logger @sessions = [] end - + def register(session) @sessions << session end - + # process until timeout # if a block is given a session will be removed from loop # if block returns false for that session def process(wait = nil, &block) return false unless ev_preprocess(&block) - + ev_select_and_postprocess(wait) end - + # process the event loop but only for the sepcified session def process_only(session, wait = nil) orig_sessions = @sessions @@ -42,7 +42,7 @@ module Net @sessions = orig_sessions end end - + # Call preprocess on each session. If block given and that # block retuns false then we exit the processing def ev_preprocess(&block) @@ -53,7 +53,7 @@ module Net return true end - + def ev_select_and_postprocess(wait) owners = {} r = [] @@ -67,11 +67,11 @@ module Net sr.each { |ri| owners[ri] = session } sw.each { |wi| owners[wi] = session } end - + readers, writers, = IO.select(r, w, nil, minwait) - + fired_sessions = {} - + if readers readers.each do |reader| session = owners[reader] @@ -84,11 +84,11 @@ module Net (fired_sessions[session] ||= { r: [],w: [] })[:w] << writer end end - + fired_sessions.each do |s,rw| s.ev_do_handle_events(rw[:r],rw[:w]) end - + @sessions.each { |s| s.ev_do_postprocess(fired_sessions.key?(s)) } true end @@ -106,14 +106,14 @@ module Net return true end - + def ev_select_and_postprocess(wait) raise "Only one session expected" unless @sessions.count == 1 session = @sessions.first sr,sw,actwait = session.ev_do_calculate_rw_wait(wait) readers, writers, = IO.select(sr, sw, nil, actwait) - + session.ev_do_handle_events(readers,writers) session.ev_do_postprocess(!((readers.nil? || readers.empty?) && (writers.nil? || writers.empty?))) end diff --git a/lib/net/ssh/connection/keepalive.rb b/lib/net/ssh/connection/keepalive.rb index 8926ba5..cdbb3e0 100644 --- a/lib/net/ssh/connection/keepalive.rb +++ b/lib/net/ssh/connection/keepalive.rb @@ -1,46 +1,46 @@ require 'net/ssh/loggable' -module Net - module SSH +module Net + module SSH module Connection class Keepalive include Loggable - + def initialize(session) @last_keepalive_sent_at = nil @unresponded_keepalive_count = 0 @session = session self.logger = session.logger end - + def options @session.options end - + def enabled? options[:keepalive] end - + def interval options[:keepalive_interval] || Session::DEFAULT_IO_SELECT_TIMEOUT end - + def should_send? return false unless enabled? return true unless @last_keepalive_sent_at Time.now - @last_keepalive_sent_at >= interval end - + def keepalive_maxcount (options[:keepalive_maxcount] || 3).to_i end - + def send_as_needed(was_events) return if was_events return unless should_send? info { "sending keepalive #{@unresponded_keepalive_count}" } - + @unresponded_keepalive_count += 1 @session.send_global_request("keepalive@openssh.com") { |success, response| debug { "keepalive response successful. Missed #{@unresponded_keepalive_count - 1} keepalives" } diff --git a/lib/net/ssh/connection/session.rb b/lib/net/ssh/connection/session.rb index 874b23f..43546fa 100644 --- a/lib/net/ssh/connection/session.rb +++ b/lib/net/ssh/connection/session.rb @@ -5,8 +5,8 @@ require 'net/ssh/service/forward' require 'net/ssh/connection/keepalive' require 'net/ssh/connection/event_loop' -module Net - module SSH +module Net + module SSH module Connection # A session class representing the connection service running on top of # the SSH transport layer. It manages the creation of channels (see @@ -27,50 +27,50 @@ module Net class Session include Loggable include Constants - + # Default IO.select timeout threshold DEFAULT_IO_SELECT_TIMEOUT = 300 - + # The underlying transport layer abstraction (see Net::SSH::Transport::Session). attr_reader :transport - + # The map of options that were used to initialize this instance. attr_reader :options - + # The collection of custom properties for this instance. (See #[] and #[]=). attr_reader :properties - + # The map of channels, each key being the local-id for the channel. attr_reader :channels #:nodoc: - + # The map of listeners that the event loop knows about. See #listen_to. attr_reader :listeners #:nodoc: - + # The map of specialized handlers for opening specific channel types. See # #on_open_channel. attr_reader :channel_open_handlers #:nodoc: - + # The list of callbacks for pending requests. See #send_global_request. attr_reader :pending_requests #:nodoc: - + class NilChannel def initialize(session) @session = session end - + def method_missing(sym, *args) @session.lwarn { "ignoring request #{sym.inspect} for non-existent (closed?) channel; probably ssh server bug" } end end - + # Create a new connection service instance atop the given transport # layer. Initializes the listeners to be only the underlying socket object. def initialize(transport, options={}) self.logger = transport.logger - + @transport = transport @options = options - + @channel_id_counter = -1 @channels = Hash.new(NilChannel.new(self)) @listeners = { transport.socket => nil } @@ -78,34 +78,34 @@ module Net @channel_open_handlers = {} @on_global_request = {} @properties = (options[:properties] || {}).dup - + @max_pkt_size = (options.key?(:max_pkt_size) ? options[:max_pkt_size] : 0x8000) @max_win_size = (options.key?(:max_win_size) ? options[:max_win_size] : 0x20000) - + @keepalive = Keepalive.new(self) - + @event_loop = options[:event_loop] || SingleSessionEventLoop.new @event_loop.register(self) end - + # Retrieves a custom property from this instance. This can be used to # store additional state in applications that must manage multiple # SSH connections. def [](key) @properties[key] end - + # Sets a custom property for this instance. def []=(key, value) @properties[key] = value end - + # Returns the name of the host that was given to the transport layer to # connect to. def host transport.host end - + # Returns true if the underlying transport has been closed. Note that # this can be a little misleading, since if the remote server has # closed the connection, the local end will still think it is open @@ -114,7 +114,7 @@ module Net def closed? transport.closed? end - + # Closes the session gracefully, blocking until all channels have # successfully closed, and then closes the underlying transport layer # connection. @@ -128,7 +128,7 @@ module Net end transport.close end - + # Performs a "hard" shutdown of the connection. In general, this should # never be done, but it might be necessary (in a rescue clause, for instance, # when the connection needs to close but you don't know the status of the @@ -136,10 +136,10 @@ module Net def shutdown! transport.shutdown! end - + # preserve a reference to Kernel#loop alias :loop_forever :loop - + # Returns +true+ if there are any channels currently active on this # session. By default, this will not include "invisible" channels # (such as those created by forwarding ports and such), but if you pass @@ -156,7 +156,7 @@ module Net channels.any? { |id, ch| !ch[:invisible] } end end - + # The main event loop. Calls #process until #process returns false. If a # block is given, it is passed to #process, otherwise a default proc is # used that just returns true if there are any channels active (see #busy?). @@ -187,7 +187,7 @@ module Net end end end - + # The core of the event loop. It processes a single iteration of the event # loop. If a block is given, it should return false when the processing # should abort, which causes #process to return false. Otherwise, @@ -228,7 +228,7 @@ module Net force_channel_cleanup_on_close if closed? raise end - + # This is called internally as part of #process. It dispatches any # available incoming packets, and then runs Net::SSH::Connection::Channel#process # for any active channels. If a block is given, it is invoked at the @@ -242,14 +242,14 @@ module Net return true end - + # Called by event loop to process available data before going to # event multiplexing def ev_preprocess(&block) dispatch_incoming_packets(raise_disconnect_errors: false) each_channel { |id, channel| channel.process unless channel.local_closed? } end - + # Returns the file descriptors the event loop should wait for read/write events, # we also return the max wait def ev_do_calculate_rw_wait(wait) @@ -257,12 +257,12 @@ module Net w = r.select { |w2| w2.respond_to?(:pending_write?) && w2.pending_write? } [r,w,io_select_wait(wait)] end - + # This is called internally as part of #process. def postprocess(readers, writers) ev_do_handle_events(readers, writers) end - + # It loops over the given arrays of reader IO's and writer IO's, # processing them as needed, and # then calls Net::SSH::Transport::Session#rekey_as_needed to allow the @@ -278,12 +278,12 @@ module Net end end end - + Array(writers).each do |writer| writer.send_pending end end - + # calls Net::SSH::Transport::Session#rekey_as_needed to allow the # transport layer to rekey def ev_do_postprocess(was_events) @@ -291,7 +291,7 @@ module Net transport.rekey_as_needed true end - + # Send a global request of the given type. The +extra+ parameters must # be even in number, and conform to the same format as described for # Net::SSH::Buffer.from. If a callback is not specified, the request will @@ -315,7 +315,7 @@ module Net pending_requests << callback if callback self end - + # Requests that a new channel be opened. By default, the channel will be # of type "session", but if you know what you're doing you can select any # of the channel types supported by the SSH protocol. The +extra+ parameters @@ -337,25 +337,25 @@ module Net # channel.wait def open_channel(type="session", *extra, &on_confirm) local_id = get_next_channel_id - + channel = Channel.new(self, type, local_id, @max_pkt_size, @max_win_size, &on_confirm) msg = Buffer.from(:byte, CHANNEL_OPEN, :string, type, :long, local_id, :long, channel.local_maximum_window_size, :long, channel.local_maximum_packet_size, *extra) send_message(msg) - + channels[local_id] = channel end - + class StringWithExitstatus < String def initialize(str, exitstatus) super(str) @exitstatus = exitstatus end - + attr_reader :exitstatus end - + # A convenience method for executing a command and interacting with it. If # no block is given, all output is printed via $stdout and $stderr. Otherwise, # the block is called for each data and extended data packet, with three @@ -380,17 +380,17 @@ module Net open_channel do |channel| channel.exec(command) do |ch, success| raise "could not execute command: #{command.inspect}" unless success - + if status channel.on_request("exit-status") do |ch2,data| status[:exit_code] = data.read_long end - + channel.on_request("exit-signal") do |ch2, data| status[:exit_signal] = data.read_long end end - + channel.on_data do |ch2, data| if block block.call(ch2, :stdout, data) @@ -398,7 +398,7 @@ module Net $stdout.print(data) end end - + channel.on_extended_data do |ch2, type, data| if block block.call(ch2, :stderr, data) @@ -409,7 +409,7 @@ module Net end end end - + # Same as #exec, except this will block until the command finishes. Also, # if no block is given, this will return all output (stdout and stderr) # as a single string. @@ -422,17 +422,17 @@ module Net ch[:result] ||= "" ch[:result] << data end - + status ||= {} channel = exec(command, status: status, &block_or_concat) channel.wait - + channel[:result] ||= "" unless block channel[:result] &&= channel[:result].force_encoding("UTF-8") unless block - + StringWithExitstatus.new(channel[:result], status[:exit_code]) if channel[:result] end - + # Enqueues a message to be sent to the server as soon as the socket is # available for writing. Most programs will never need to call this, but # if you are implementing an extension to the SSH protocol, or if you @@ -443,7 +443,7 @@ module Net def send_message(message) transport.enqueue_message(message) end - + # Adds an IO object for the event loop to listen to. If a callback # is given, it will be invoked when the io is ready to be read, otherwise, # the io will merely have its #fill method invoked. @@ -481,19 +481,19 @@ module Net def listen_to(io, &callback) listeners[io] = callback end - + # Removes the given io object from the listeners collection, so that the # event loop will no longer monitor it. def stop_listening_to(io) listeners.delete(io) end - + # Returns a reference to the Net::SSH::Service::Forward service, which can # be used for forwarding ports over SSH. def forward @forward ||= Service::Forward.new(self) end - + # Registers a handler to be invoked when the server wants to open a # channel on the client. The callback receives the connection object, # the new channel object, and the packet itself as arguments, and should @@ -507,7 +507,7 @@ module Net def on_open_channel(type, &block) channel_open_handlers[type] = block end - + # Registers a handler to be invoked when the server sends a global request # of the given type. The callback receives the request data as the first # parameter, and true/false as the second (indicating whether a response @@ -518,61 +518,61 @@ module Net old, @on_global_request[type] = @on_global_request[type], block old end - + def cleanup_channel(channel) if channel.local_closed? and channel.remote_closed? info { "#{host} delete channel #{channel.local_id} which closed locally and remotely" } channels.delete(channel.local_id) end end - + # If the #preprocess and #postprocess callbacks for this session need to run # periodically, this method returns the maximum number of seconds which may # pass between callbacks. def max_select_wait_time @keepalive.interval if @keepalive.enabled? end - + private - + # iterate channels with the posibility of callbacks opening new channels during the iteration def each_channel(&block) channels.dup.each(&block) end - + # Read all pending packets from the connection and dispatch them as # appropriate. Returns as soon as there are no more pending packets. def dispatch_incoming_packets(raise_disconnect_errors: true) while packet = transport.poll_message raise Net::SSH::Exception, "unexpected response #{packet.type} (#{packet.inspect})" unless MAP.key?(packet.type) - + send(MAP[packet.type], packet) end rescue StandardError force_channel_cleanup_on_close if closed? raise if raise_disconnect_errors || !$!.is_a?(Net::SSH::Disconnect) end - + # Returns the next available channel id to be assigned, and increments # the counter. def get_next_channel_id @channel_id_counter += 1 end - + def force_channel_cleanup_on_close channels.each do |id, channel| channel_closed(channel) end end - + def channel_closed(channel) channel.remote_closed! channel.close - + cleanup_channel(channel) channel.do_close end - + # Invoked when a global request is received. The registered global # request callback will be invoked, if one exists, and the necessary # reply returned. @@ -584,41 +584,41 @@ module Net if result != :sent && result != true && result != false raise "expected global request handler for `#{packet[:request_type]}' to return true, false, or :sent, but got #{result.inspect}" end - + if packet[:want_reply] && result != :sent msg = Buffer.from(:byte, result ? REQUEST_SUCCESS : REQUEST_FAILURE) send_message(msg) end end - + # Invokes the next pending request callback with +true+. def request_success(packet) info { "global request success" } callback = pending_requests.shift callback.call(true, packet) if callback end - + # Invokes the next pending request callback with +false+. def request_failure(packet) info { "global request failure" } callback = pending_requests.shift callback.call(false, packet) if callback end - + # Called when the server wants to open a channel. If no registered # channel handler exists for the given channel type, CHANNEL_OPEN_FAILURE # is returned, otherwise the callback is invoked and everything proceeds # accordingly. def channel_open(packet) info { "channel open #{packet[:channel_type]}" } - + local_id = get_next_channel_id - + channel = Channel.new(self, packet[:channel_type], local_id, @max_pkt_size, @max_win_size) channel.do_open_confirmation(packet[:remote_id], packet[:window_size], packet[:packet_size]) - + callback = channel_open_handlers[packet[:channel_type]] - + if callback begin callback[self, channel, packet] @@ -633,73 +633,73 @@ module Net else failure = [3, "unknown channel type #{channel.type}"] end - + if failure error { failure.inspect } msg = Buffer.from(:byte, CHANNEL_OPEN_FAILURE, :long, channel.remote_id, :long, failure[0], :string, failure[1], :string, "") end - + send_message(msg) end - + def channel_open_confirmation(packet) info { "channel_open_confirmation: #{packet[:local_id]} #{packet[:remote_id]} #{packet[:window_size]} #{packet[:packet_size]}" } channel = channels[packet[:local_id]] channel.do_open_confirmation(packet[:remote_id], packet[:window_size], packet[:packet_size]) end - + def channel_open_failure(packet) error { "channel_open_failed: #{packet[:local_id]} #{packet[:reason_code]} #{packet[:description]}" } channel = channels.delete(packet[:local_id]) channel.do_open_failed(packet[:reason_code], packet[:description]) end - + def channel_window_adjust(packet) info { "channel_window_adjust: #{packet[:local_id]} +#{packet[:extra_bytes]}" } channels[packet[:local_id]].do_window_adjust(packet[:extra_bytes]) end - + def channel_request(packet) info { "channel_request: #{packet[:local_id]} #{packet[:request]} #{packet[:want_reply]}" } channels[packet[:local_id]].do_request(packet[:request], packet[:want_reply], packet[:request_data]) end - + def channel_data(packet) info { "channel_data: #{packet[:local_id]} #{packet[:data].length}b" } channels[packet[:local_id]].do_data(packet[:data]) end - + def channel_extended_data(packet) info { "channel_extended_data: #{packet[:local_id]} #{packet[:data_type]} #{packet[:data].length}b" } channels[packet[:local_id]].do_extended_data(packet[:data_type], packet[:data]) end - + def channel_eof(packet) info { "channel_eof: #{packet[:local_id]}" } channels[packet[:local_id]].do_eof end - + def channel_close(packet) info { "channel_close: #{packet[:local_id]}" } - + channel = channels[packet[:local_id]] channel_closed(channel) end - + def channel_success(packet) info { "channel_success: #{packet[:local_id]}" } channels[packet[:local_id]].do_success end - + def channel_failure(packet) info { "channel_failure: #{packet[:local_id]}" } channels[packet[:local_id]].do_failure end - + def io_select_wait(wait) [wait, max_select_wait_time].compact.min end - + MAP = Constants.constants.each_with_object({}) do |name, memo| value = const_get(name) next unless Integer === value diff --git a/lib/net/ssh/connection/term.rb b/lib/net/ssh/connection/term.rb index ef32910..d4abad1 100644 --- a/lib/net/ssh/connection/term.rb +++ b/lib/net/ssh/connection/term.rb @@ -1,7 +1,6 @@ -module Net - module SSH +module Net + module SSH module Connection - # These constants are used when requesting a pseudo-terminal (via # Net::SSH::Connection::Channel#request_pty). The descriptions for each are # taken directly from RFC 4254 ("The Secure Shell (SSH) Connection Protocol"), @@ -10,169 +9,169 @@ module Net # Interrupt character; 255 if none. Similarly for the other characters. # Not all of these characters are supported on all systems. VINTR = 1 - + # The quit character (sends SIGQUIT signal on POSIX systems). VQUIT = 2 - + # Erase the character to left of the cursor. VERASE = 3 - + # Kill the current input line. VKILL = 4 - + # End-of-file character (sends EOF from the terminal). VEOF = 5 - + # End-of-line character in addition to carriage return and/or linefeed. VEOL = 6 - + # Additional end-of-line character. VEOL2 = 7 - + # Continues paused output (normally control-Q). VSTART = 8 - + # Pauses output (normally control-S). VSTOP = 9 - + # Suspends the current program. VSUSP = 10 - + # Another suspend character. VDSUSP = 11 - + # Reprints the current input line. VREPRINT = 12 - + # Erases a word left of cursor. VWERASE = 13 - + # Enter the next character typed literally, even if it is a special # character. VLNEXT = 14 - + # Character to flush output. VFLUSH = 15 - + # Switch to a different shell layer. VSWITCH = 16 - + # Prints system status line (load, command, pid, etc). VSTATUS = 17 - + # Toggles the flushing of terminal output. VDISCARD = 18 - + # The ignore parity flag. The parameter SHOULD be 0 if this flag is FALSE, # and 1 if it is TRUE. IGNPAR = 30 - + # Mark parity and framing errors. PARMRK = 31 - + # Enable checking of parity errors. INPCK = 32 - + # Strip 8th bit off characters. ISTRIP = 33 - + # Map NL into CR on input. INCLR = 34 - + # Ignore CR on input. IGNCR = 35 - + # Map CR to NL on input. ICRNL = 36 - + # Translate uppercase characters to lowercase. IUCLC = 37 - + # Enable output flow control. IXON = 38 - + # Any char will restart after stop. IXANY = 39 - + # Enable input flow control. IXOFF = 40 - + # Ring bell on input queue full. IMAXBEL = 41 - + # Enable signals INTR, QUIT, [D]SUSP. ISIG = 50 - + # Canonicalize input lines. ICANON = 51 - + # Enable input and output of uppercase characters by preceding their # lowercase equivalents with "\". XCASE = 52 - + # Enable echoing. ECHO = 53 - + # Visually erase chars. ECHOE = 54 - + # Kill character discards current line. ECHOK = 55 - + # Echo NL even if ECHO is off. ECHONL = 56 - + # Don't flush after interrupt. NOFLSH = 57 - + # Stop background jobs from output. TOSTOP = 58 - + # Enable extensions. IEXTEN = 59 - + # Echo control characters as ^(Char). ECHOCTL = 60 - + # Visual erase for line kill. ECHOKE = 61 - + # Retype pending input. PENDIN = 62 - + # Enable output processing. OPOST = 70 - + # Convert lowercase to uppercase. OLCUC = 71 - + # Map NL to CR-NL. ONLCR = 72 - + # Translate carriage return to newline (output). OCRNL = 73 - + # Translate newline to carriage return-newline (output). ONOCR = 74 - + # Newline performs a carriage return (output). ONLRET = 75 - + # 7 bit mode. CS7 = 90 - + # 8 bit mode. CS8 = 91 - + # Parity enable. PARENB = 92 - + # Odd parity, else even. PARODD = 93 - + # Specifies the input baud rate in bits per second. TTY_OP_ISPEED = 128 - + # Specifies the output baud rate in bits per second. TTY_OP_OSPEED = 129 end diff --git a/lib/net/ssh/errors.rb b/lib/net/ssh/errors.rb index 8fa8a4b..c445459 100644 --- a/lib/net/ssh/errors.rb +++ b/lib/net/ssh/errors.rb @@ -1,4 +1,4 @@ -module Net +module Net module SSH # A general exception class, to act as the ancestor of all other Net::SSH # exception classes. @@ -33,7 +33,7 @@ module Net # a "channel open failed" message. class ChannelOpenFailed < Net::SSH::Exception attr_reader :code, :reason - + def initialize(code, reason) @code, @reason = code, reason super "#{reason} (#{code})" @@ -46,42 +46,42 @@ module Net class HostKeyError < Net::SSH::Exception # the callback to use when #remember_host! is called attr_writer :callback #:nodoc: - + # situation-specific data describing the host (see #host, #port, etc.) attr_writer :data #:nodoc: - + # An accessor for getting at the data that was used to look up the host # (see also #fingerprint, #host, #port, #ip, and #key). def [](key) @data && @data[key] end - + # Returns the fingerprint of the key for the host, which either was not # found or did not match. def fingerprint @data && @data[:fingerprint] end - + # Returns the host name for the remote host, as reported by the socket. def host @data && @data[:peer] && @data[:peer][:host] end - + # Returns the port number for the remote host, as reported by the socket. def port @data && @data[:peer] && @data[:peer][:port] end - + # Returns the IP address of the remote host, as reported by the socket. def ip @data && @data[:peer] && @data[:peer][:ip] end - + # Returns the key itself, as reported by the remote host. def key @data && @data[:key] end - + # Tell Net::SSH to record this host and key in the known hosts file, so # that subsequent connections will remember them. def remember_host! diff --git a/lib/net/ssh/loggable.rb b/lib/net/ssh/loggable.rb index 15ea750..49ea5dd 100644 --- a/lib/net/ssh/loggable.rb +++ b/lib/net/ssh/loggable.rb @@ -1,4 +1,4 @@ -module Net +module Net module SSH # A simple module to make logging easier to deal with. It assumes that the # logger instance (if not nil) quacks like a Logger object (in Ruby's @@ -18,39 +18,39 @@ module Net # The logger instance that will be used to log messages. If nil, nothing # will be logged. attr_accessor :logger - + # Displays the result of yielding if the log level is Logger::DEBUG or # greater. def debug logger.add(Logger::DEBUG, nil, facility) { yield } if logger && logger.debug? end - + # Displays the result of yielding if the log level is Logger::INFO or # greater. def info logger.add(Logger::INFO, nil, facility) { yield } if logger && logger.info? end - + # Displays the result of yielding if the log level is Logger::WARN or # greater. (Called lwarn to avoid shadowing with Kernel#warn.) def lwarn logger.add(Logger::WARN, nil, facility) { yield } if logger && logger.warn? end - + # Displays the result of yielding if the log level is Logger:ERROR or # greater. def error logger.add(Logger::ERROR, nil, facility) { yield } if logger && logger.error? end - + # Displays the result of yielding if the log level is Logger::FATAL or # greater. def fatal logger.add(Logger::FATAL, nil, facility) { yield } if logger && logger.fatal? end - + private - + # Sets the "facility" value, used for reporting where a log message # originates. It defaults to the name of class with the object_id # appended. diff --git a/lib/net/ssh/prompt.rb b/lib/net/ssh/prompt.rb index 98715c5..e47d71e 100644 --- a/lib/net/ssh/prompt.rb +++ b/lib/net/ssh/prompt.rb @@ -1,6 +1,6 @@ require 'io/console' -module Net +module Net module SSH # Default prompt implementation, called for asking password from user. # It will never be instantiated directly, but will instead be created for @@ -23,9 +23,9 @@ module Net def self.default(options = {}) @default ||= new(options) end - + def initialize(options = {}); end - + # default prompt object implementation. More sophisticated implemenetations # might implement caching. class Prompter @@ -35,7 +35,7 @@ module Net $stdout.puts(info[:instruction]) unless info[:instruction].empty? end end - + # ask input from user, a prompter might ask for multiple inputs # (like user and password) in a single session. def ask(prompt, echo=true) @@ -45,12 +45,12 @@ module Net $stdout.print("\n") ret end - + # success method will be called when the password was accepted # It's a good time to save password asked to a cache. def success; end end - + # start password session. Multiple questions might be asked multiple times # on the returned object. Info hash tries to uniquely identify the password # session, so caching implementations can save passwords properly. diff --git a/lib/net/ssh/proxy/errors.rb b/lib/net/ssh/proxy/errors.rb index d7e5458..f696cf3 100644 --- a/lib/net/ssh/proxy/errors.rb +++ b/lib/net/ssh/proxy/errors.rb @@ -1,7 +1,7 @@ require 'net/ssh/errors' -module Net - module SSH +module Net + module SSH module Proxy # A general exception class for all Proxy errors. class Error < Net::SSH::Exception; end diff --git a/lib/net/ssh/proxy/http.rb b/lib/net/ssh/proxy/http.rb index cf94634..e7dc3d0 100644 --- a/lib/net/ssh/proxy/http.rb +++ b/lib/net/ssh/proxy/http.rb @@ -1,8 +1,8 @@ require 'socket' require 'net/ssh/proxy/errors' -module Net - module SSH +module Net + module SSH module Proxy # An implementation of an HTTP proxy. To use it, instantiate it, then # pass the instantiated object via the :proxy key to Net::SSH.start: @@ -25,14 +25,14 @@ module Net class HTTP # The hostname or IP address of the HTTP proxy. attr_reader :proxy_host - + # The port number of the proxy. attr_reader :proxy_port - + # The map of additional options that were given to the object at # initialization. attr_reader :options - + # Create a new socket factory that tunnels via the given host and # port. The +options+ parameter is a hash of additional settings that # can be used to tweak this proxy connection. Specifically, the following @@ -45,47 +45,47 @@ module Net @proxy_port = proxy_port @options = options end - + # Return a new socket connected to the given host and port via the # proxy that was requested when the socket factory was instantiated. def open(host, port, connection_options) socket = establish_connection(connection_options[:timeout]) socket.write "CONNECT #{host}:#{port} HTTP/1.1\r\n" socket.write "Host: #{host}:#{port}\r\n" - + if options[:user] credentials = ["#{options[:user]}:#{options[:password]}"].pack("m*").gsub(/\s/, "") socket.write "Proxy-Authorization: Basic #{credentials}\r\n" end - + socket.write "\r\n" - + resp = parse_response(socket) - + return socket if resp[:code] == 200 - + socket.close raise ConnectError, resp.inspect end - + protected - + def establish_connection(connect_timeout) Socket.tcp(proxy_host, proxy_port, nil, nil, connect_timeout: connect_timeout) end - + def parse_response(socket) version, code, reason = socket.gets.chomp.split(/ /, 3) headers = {} - + while (line = socket.gets) && (line.chomp! != "") name, value = line.split(/:/, 2) headers[name.strip] = value.strip end - + body = socket.read(headers["Content-Length"].to_i) if headers["Content-Length"] - + return { version: version, code: code.to_i, reason: reason, diff --git a/lib/net/ssh/proxy/https.rb b/lib/net/ssh/proxy/https.rb index a0da2a4..4f4fdb2 100644 --- a/lib/net/ssh/proxy/https.rb +++ b/lib/net/ssh/proxy/https.rb @@ -3,8 +3,8 @@ require 'openssl' require 'net/ssh/proxy/errors' require 'net/ssh/proxy/http' -module Net - module SSH +module Net + module SSH module Proxy # A specialization of the HTTP proxy which encrypts the whole connection # using OpenSSL. This has the advantage that proxy authentication @@ -21,9 +21,9 @@ module Net OpenSSL::SSL::SSLContext.new super(proxy_host, proxy_port, options) end - + protected - + # Shim to make OpenSSL::SSL::SSLSocket behave like a regular TCPSocket # for all intents and purposes of Net::SSH::BufferedIo module SSLSocketCompatibility @@ -31,12 +31,12 @@ module Net object.define_singleton_method(:recv, object.method(:sysread)) object.sync_close = true end - + def send(data, _opts) syswrite(data) end end - + def establish_connection(connect_timeout) plain_socket = super(connect_timeout) OpenSSL::SSL::SSLSocket.new(plain_socket, @ssl_context).tap do |socket| diff --git a/lib/net/ssh/proxy/jump.rb b/lib/net/ssh/proxy/jump.rb index b92dcdc..0630bd8 100644 --- a/lib/net/ssh/proxy/jump.rb +++ b/lib/net/ssh/proxy/jump.rb @@ -1,8 +1,8 @@ require 'uri' require 'net/ssh/proxy/command' -module Net - module SSH +module Net + module SSH module Proxy # An implementation of a jump proxy. To use it, instantiate it, # then pass the instantiated object via the :proxy key to @@ -17,27 +17,27 @@ module Net class Jump < Command # The jump proxies attr_reader :jump_proxies - + # Create a new socket factory that tunnels via multiple jump proxes as # [user@]host[:port]. def initialize(jump_proxies) @jump_proxies = jump_proxies end - + # Return a new socket connected to the given host and port via the jump # proxy that was requested when the socket factory was instantiated. def open(host, port, connection_options = nil) build_proxy_command_equivalent(connection_options) super end - + # We cannot build the ProxyCommand template until we know if the :config # option was specified during `Net::SSH.start`. def build_proxy_command_equivalent(connection_options = nil) first_jump, extra_jumps = jump_proxies.split(",", 2) config = connection_options && connection_options[:config] uri = URI.parse("ssh://#{first_jump}") - + template = "ssh" template << " -l #{uri.user}" if uri.user template << " -p #{uri.port}" if uri.port @@ -45,7 +45,7 @@ module Net template << " -F #{config}" if config != true && config template << " -W %h:%p " template << uri.host - + @command_line_template = template end end diff --git a/lib/net/ssh/proxy/socks4.rb b/lib/net/ssh/proxy/socks4.rb index ddd95b0..a964d1e 100644 --- a/lib/net/ssh/proxy/socks4.rb +++ b/lib/net/ssh/proxy/socks4.rb @@ -49,7 +49,7 @@ module Net socket = Socket.tcp(proxy_host, proxy_port, nil, nil, connect_timeout: connection_options[:timeout]) ip_addr = IPAddr.new(Resolv.getaddress(host)) - + packet = [VERSION, CONNECT, port.to_i, ip_addr.to_i, options[:user]].pack("CCnNZ*") socket.send packet, 0 diff --git a/lib/net/ssh/proxy/socks5.rb b/lib/net/ssh/proxy/socks5.rb index 77300cd..8a0ae91 100644 --- a/lib/net/ssh/proxy/socks5.rb +++ b/lib/net/ssh/proxy/socks5.rb @@ -93,7 +93,7 @@ module Net packet << [port].pack("n") socket.send packet, 0 - + version, reply, = socket.recv(2).unpack("C*") socket.recv(1) address_type = socket.recv(1).getbyte(0) @@ -110,7 +110,7 @@ module Net raise ConnectError, "Illegal response type" end portnum = socket.recv(2) - + unless reply == SUCCESS socket.close raise ConnectError, "#{reply}" diff --git a/lib/net/ssh/test/channel.rb b/lib/net/ssh/test/channel.rb index 9a46ab3..3ee56e2 100644 --- a/lib/net/ssh/test/channel.rb +++ b/lib/net/ssh/test/channel.rb @@ -1,5 +1,5 @@ -module Net - module SSH +module Net + module SSH module Test # A mock channel, used for scripting actions in tests. It wraps a # Net::SSH::Test::Script instance, and delegates to it for the most part. @@ -18,34 +18,34 @@ module Net class Channel # The Net::SSH::Test::Script instance employed by this mock channel. attr_reader :script - + # Sets the local-id of this channel object (the id assigned by the client). attr_writer :local_id - + # Sets the remote-id of this channel object (the id assigned by the mock-server). attr_writer :remote_id - + # Creates a new Test::Channel instance on top of the given +script+ (which # must be a Net::SSH::Test::Script instance). def initialize(script) @script = script @local_id = @remote_id = nil end - + # Returns the local (client-assigned) id for this channel, or a Proc object # that will return the local-id later if the local id has not yet been set. # (See Net::SSH::Test::Packet#instantiate!.) def local_id @local_id || Proc.new { @local_id or raise "local-id has not been set yet!" } end - + # Returns the remote (server-assigned) id for this channel, or a Proc object # that will return the remote-id later if the remote id has not yet been set. # (See Net::SSH::Test::Packet#instantiate!.) def remote_id @remote_id || Proc.new { @remote_id or raise "remote-id has not been set yet!" } end - + # Because adjacent calls to #gets_data will sometimes cause the data packets # to be concatenated (causing expectations in tests to fail), you may # need to separate those calls with calls to #inject_remote_delay! (which @@ -57,8 +57,8 @@ module Net def inject_remote_delay! gets_data("") end - - # Scripts the sending of an "exec" channel request packet to the mock + + # Scripts the sending of an "exec" channel request packet to the mock # server. If +reply+ is true, then the server is expected to reply to the # request, otherwise no response to this request will be sent. If +success+ # is +true+, then the request will be successful, otherwise a failure will @@ -68,7 +68,7 @@ module Net def sends_exec(command, reply=true, success=true) script.sends_channel_request(self, "exec", reply, command, success) end - + # Scripts the sending of a "subsystem" channel request packet to the mock # server. See #sends_exec for a discussion of the meaning of the +reply+ # and +success+ arguments. @@ -77,42 +77,42 @@ module Net def sends_subsystem(subsystem, reply=true, success=true) script.sends_channel_request(self, "subsystem", reply, subsystem, success) end - + # Scripts the sending of a data packet across the channel. # # channel.sends_data "foo" def sends_data(data) script.sends_channel_data(self, data) end - + # Scripts the sending of an EOF packet across the channel. # # channel.sends_eof def sends_eof script.sends_channel_eof(self) end - + # Scripts the sending of a "channel close" packet across the channel. # # channel.sends_close def sends_close script.sends_channel_close(self) end - + # Scripts the sending of a "request pty" request packet across the channel. # # channel.sends_request_pty def sends_request_pty script.sends_channel_request_pty(self) end - + # Scripts the reception of a channel data packet from the remote end. # # channel.gets_data "bar" def gets_data(data) script.gets_channel_data(self, data) end - + # Scripts the reception of a channel extended data packet from the remote # end. # @@ -120,21 +120,21 @@ module Net def gets_extended_data(data) script.gets_channel_extended_data(self, data) end - + # Scripts the reception of an "exit-status" channel request packet. # # channel.gets_exit_status(127) def gets_exit_status(status=0) script.gets_channel_request(self, "exit-status", false, status) end - + # Scripts the reception of an EOF packet from the remote end. # # channel.gets_eof def gets_eof script.gets_channel_eof(self) end - + # Scripts the reception of a "channel close" packet from the remote end. # # channel.gets_close diff --git a/lib/net/ssh/test/extensions.rb b/lib/net/ssh/test/extensions.rb index 91bb2d6..527c88b 100644 --- a/lib/net/ssh/test/extensions.rb +++ b/lib/net/ssh/test/extensions.rb @@ -6,15 +6,14 @@ require 'net/ssh/connection/constants' require 'net/ssh/transport/constants' require 'net/ssh/transport/packet_stream' -module Net - module SSH +module Net + module SSH module Test # A collection of modules used to extend/override the default behavior of # Net::SSH internals for ease of testing. As a consumer of Net::SSH, you'll # never need to use this directly--they're all used under the covers by # the Net::SSH::Test system. module Extensions - # An extension to Net::SSH::BufferedIo (assumes that the underlying IO # is actually a StringIO). Facilitates unit testing. module BufferedIo @@ -23,48 +22,48 @@ module Net def select_for_read? pos < size end - + # Set this to +true+ if you want the IO to pretend to be available for writing attr_accessor :select_for_write - + # Set this to +true+ if you want the IO to pretend to be in an error state attr_accessor :select_for_error - + alias select_for_write? select_for_write alias select_for_error? select_for_error end - + # An extension to Net::SSH::Transport::PacketStream (assumes that the # underlying IO is actually a StringIO). Facilitates unit testing. module PacketStream include BufferedIo # make sure we get the extensions here, too - + def self.included(base) #:nodoc: base.send :alias_method, :real_available_for_read?, :available_for_read? base.send :alias_method, :available_for_read?, :test_available_for_read? - + base.send :alias_method, :real_enqueue_packet, :enqueue_packet base.send :alias_method, :enqueue_packet, :test_enqueue_packet - + base.send :alias_method, :real_poll_next_packet, :poll_next_packet base.send :alias_method, :poll_next_packet, :test_poll_next_packet end - + # Called when another packet should be inspected from the current # script. If the next packet is a remote packet, it pops it off the # script and shoves it onto this IO object, making it available to # be read. def idle! return false unless script.next(:first) - + if script.next(:first).remote? self.string << script.next.to_s self.pos = pos end - + return true end - + # The testing version of Net::SSH::Transport::PacketStream#available_for_read?. # Returns true if there is data pending to be read. Otherwise calls #idle!. def test_available_for_read? @@ -73,14 +72,14 @@ module Net idle! false end - + # The testing version of Net::SSH::Transport::PacketStream#enqueued_packet. # Simply calls Net::SSH::Test::Script#process on the packet. def test_enqueue_packet(payload) packet = Net::SSH::Buffer.new(payload.to_s) script.process(packet) end - + # The testing version of Net::SSH::Transport::PacketStream#poll_next_packet. # Reads the next available packet from the IO object and returns it. def test_poll_next_packet @@ -91,14 +90,14 @@ module Net Net::SSH::Packet.new(read_available(length)) end end - + # An extension to Net::SSH::Connection::Channel. Facilitates unit testing. module Channel def self.included(base) #:nodoc: base.send :alias_method, :send_data_for_real, :send_data base.send :alias_method, :send_data, :send_data_for_test end - + # The testing version of Net::SSH::Connection::Channel#send_data. Calls # the original implementation, and then immediately enqueues the data for # output so that scripted sends are properly interpreted as discrete @@ -108,16 +107,16 @@ module Net enqueue_pending_output end end - + # An extension to the built-in ::IO class. Simply redefines IO.select # so that it can be scripted in Net::SSH unit tests. module IO def self.included(base) #:nodoc: base.extend(ClassMethods) end - + @extension_enabled = false - + def self.with_test_extension(&block) orig_value = @extension_enabled @extension_enabled = true @@ -127,11 +126,11 @@ module Net @extension_enabled = orig_value end end - + def self.extension_enabled? @extension_enabled end - + module ClassMethods def self.extended(obj) #:nodoc: class <<obj @@ -139,7 +138,7 @@ module Net alias_method :select, :select_for_test end end - + # The testing version of ::IO.select. Assumes that all readers, # writers, and errors arrays are either nil, or contain only objects # that mix in Net::SSH::Test::Extensions::BufferedIo. @@ -149,14 +148,14 @@ module Net ready_readers = Array(readers).select { |r| r.select_for_read? } ready_writers = Array(writers).select { |r| r.select_for_write? } ready_errors = Array(errors).select { |r| r.select_for_error? } - + return [ready_readers, ready_writers, ready_errors] if ready_readers.any? || ready_writers.any? || ready_errors.any? - + processed = 0 Array(readers).each do |reader| processed += 1 if reader.idle! end - + raise "no readers were ready for reading, and none had any incoming packets" if processed == 0 && wait != 0 [[], [], []] diff --git a/lib/net/ssh/test/kex.rb b/lib/net/ssh/test/kex.rb index e8a0392..9e6f5be 100644 --- a/lib/net/ssh/test/kex.rb +++ b/lib/net/ssh/test/kex.rb @@ -5,8 +5,8 @@ require 'net/ssh/transport/algorithms' require 'net/ssh/transport/constants' require 'net/ssh/transport/kex' -module Net - module SSH +module Net + module SSH module Test # An implementation of a key-exchange strategy specifically for unit tests. # (This strategy would never really work against a real SSH server--it makes @@ -16,22 +16,22 @@ module Net # "test" algorithm. class Kex include Net::SSH::Transport::Constants - + # Creates a new instance of the testing key-exchange algorithm with the # given arguments. def initialize(algorithms, connection, data) @connection = connection end - + # Exchange keys with the server. This returns a hash of constant values, # and does not actually exchange keys. def exchange_keys result = Net::SSH::Buffer.from(:byte, NEWKEYS) @connection.send_message(result) - + buffer = @connection.next_message raise Net::SSH::Exception, "expected NEWKEYS" unless buffer.type == NEWKEYS - + { session_id: "abc-xyz", server_key: OpenSSL::PKey::RSA.new(512), shared_secret: OpenSSL::BN.new("1234567890", 10), diff --git a/lib/net/ssh/test/remote_packet.rb b/lib/net/ssh/test/remote_packet.rb index 34051f1..8f7bde2 100644 --- a/lib/net/ssh/test/remote_packet.rb +++ b/lib/net/ssh/test/remote_packet.rb @@ -1,8 +1,8 @@ require 'net/ssh/buffer' require 'net/ssh/test/packet' -module Net - module SSH +module Net + module SSH module Test # This is a specialization of Net::SSH::Test::Packet for representing mock # packets that are received by the local (client) host. These are created @@ -13,7 +13,7 @@ module Net def remote? true end - + # The #process method should only be called on Net::SSH::Test::LocalPacket # packets; if it is attempted on a remote packet, then it is an expectation # mismatch (a remote packet was received when a local packet was expected @@ -22,8 +22,8 @@ module Net def process(packet) raise "received packet type #{packet.read_byte} and was not expecting any packet" end - - # Returns this remote packet as a string, suitable for parsing by + + # Returns this remote packet as a string, suitable for parsing by # Net::SSH::Transport::PacketStream and friends. When a remote packet is # received, this method is called and the result concatenated onto the # input buffer for the packet stream. diff --git a/lib/net/ssh/test/script.rb b/lib/net/ssh/test/script.rb index e7cef09..7879ad7 100644 --- a/lib/net/ssh/test/script.rb +++ b/lib/net/ssh/test/script.rb @@ -2,8 +2,8 @@ require 'net/ssh/test/channel' require 'net/ssh/test/local_packet' require 'net/ssh/test/remote_packet' -module Net - module SSH +module Net + module SSH module Test # Represents a sequence of scripted events that identify the behavior that # a test expects. Methods named "sends_*" create events for packets being @@ -21,12 +21,12 @@ module Net # The list of scripted events. These will be Net::SSH::Test::LocalPacket # and Net::SSH::Test::RemotePacket instances. attr_reader :events - + # Create a new, empty script. def initialize @events = [] end - + # Scripts the opening of a channel by adding a local packet sending the # channel open request, and if +confirm+ is true (the default), also # adding a remote packet confirming the new channel. @@ -36,26 +36,26 @@ module Net def opens_channel(confirm=true) channel = Channel.new(self) channel.remote_id = 5555 - + events << LocalPacket.new(:channel_open) { |p| channel.local_id = p[:remote_id] } - + events << RemotePacket.new(:channel_open_confirmation, channel.local_id, channel.remote_id, 0x20000, 0x10000) if confirm - + channel end - + # A convenience method for adding an arbitrary local packet to the events # list. def sends(type, *args, &block) events << LocalPacket.new(type, *args, &block) end - + # A convenience method for adding an arbitrary remote packet to the events # list. def gets(type, *args) events << RemotePacket.new(type, *args) end - + # Scripts the sending of a new channel request packet to the remote host. # +channel+ should be an instance of Net::SSH::Test::Channel. +request+ # is a string naming the request type to send, +reply+ is a boolean @@ -84,7 +84,7 @@ module Net end end end - + # Scripts the sending of a channel data packet. +channel+ must be a # Net::SSH::Test::Channel object, and +data+ is the (string) data to # expect will be sent. @@ -93,21 +93,21 @@ module Net def sends_channel_data(channel, data) events << LocalPacket.new(:channel_data, channel.remote_id, data) end - + # Scripts the sending of a channel EOF packet from the given # Net::SSH::Test::Channel +channel+. This will typically be called via # Net::SSH::Test::Channel#sends_eof. def sends_channel_eof(channel) events << LocalPacket.new(:channel_eof, channel.remote_id) end - + # Scripts the sending of a channel close packet from the given # Net::SSH::Test::Channel +channel+. This will typically be called via # Net::SSH::Test::Channel#sends_close. def sends_channel_close(channel) events << LocalPacket.new(:channel_close, channel.remote_id) end - + # Scripts the sending of a channel request pty packets from the given # Net::SSH::Test::Channel +channel+. This will typically be called via # Net::SSH::Test::Channel#sends_request_pty. @@ -116,14 +116,14 @@ module Net data += Net::SSH::Connection::Channel::VALID_PTY_OPTIONS.merge(modes: "\0").values events << LocalPacket.new(:channel_request, channel.remote_id, *data) end - + # Scripts the reception of a channel data packet from the remote host by # the given Net::SSH::Test::Channel +channel+. This will typically be # called via Net::SSH::Test::Channel#gets_data. def gets_channel_data(channel, data) events << RemotePacket.new(:channel_data, channel.local_id, data) end - + # Scripts the reception of a channel extended data packet from the remote # host by the given Net::SSH::Test::Channel +channel+. This will typically # be called via Net::SSH::Test::Channel#gets_extended_data. @@ -132,28 +132,28 @@ module Net def gets_channel_extended_data(channel, data) events << RemotePacket.new(:channel_extended_data, channel.local_id, 1, data) end - + # Scripts the reception of a channel request packet from the remote host by # the given Net::SSH::Test::Channel +channel+. This will typically be # called via Net::SSH::Test::Channel#gets_exit_status. def gets_channel_request(channel, request, reply, data) events << RemotePacket.new(:channel_request, channel.local_id, request, reply, data) end - + # Scripts the reception of a channel EOF packet from the remote host by # the given Net::SSH::Test::Channel +channel+. This will typically be # called via Net::SSH::Test::Channel#gets_eof. def gets_channel_eof(channel) events << RemotePacket.new(:channel_eof, channel.local_id) end - + # Scripts the reception of a channel close packet from the remote host by # the given Net::SSH::Test::Channel +channel+. This will typically be # called via Net::SSH::Test::Channel#gets_close. def gets_channel_close(channel) events << RemotePacket.new(:channel_close, channel.local_id) end - + # By default, removes the next event in the list and returns it. However, # this can also be used to non-destructively peek at the next event in the # list, by passing :first as the argument. @@ -166,7 +166,7 @@ module Net def next(mode=:shift) events.send(mode) end - + # Compare the given packet against the next event in the list. If there is # no next event, an exception will be raised. This is called by # Net::SSH::Test::Extensions::PacketStream#test_enqueue_packet. diff --git a/lib/net/ssh/test/socket.rb b/lib/net/ssh/test/socket.rb index c5e781f..42ece27 100644 --- a/lib/net/ssh/test/socket.rb +++ b/lib/net/ssh/test/socket.rb @@ -3,63 +3,62 @@ require 'stringio' require 'net/ssh/test/extensions' require 'net/ssh/test/script' -module Net - module SSH +module Net + module SSH module Test # A mock socket implementation for use in testing. It implements the minimum # necessary interface for interacting with the rest of the Net::SSH::Test # system. class Socket < StringIO attr_reader :host, :port - + # The Net::SSH::Test::Script object in use by this socket. This is the # canonical script instance that should be used for any test depending on # this socket instance. attr_reader :script - + # Create a new test socket. This will also instantiate a new Net::SSH::Test::Script # and seed it with the necessary events to power the initialization of the # connection. def initialize extend(Net::SSH::Transport::PacketStream) super "SSH-2.0-Test\r\n" - + @script = Script.new - + script.sends(:kexinit) script.gets(:kexinit, 1, 2, 3, 4, "test", "ssh-rsa", "none", "none", "none", "none", "none", "none", "", "", false) script.sends(:newkeys) script.gets(:newkeys) end - + # This doesn't actually do anything, since we don't really care what gets # written. def write(data) # black hole, because we don't actually care about what gets written end - + # Allows the socket to also mimic a socket factory, simply returning # +self+. def open(host, port, options={}) @host, @port = host, port self end - + # Returns a sockaddr struct for the port and host that were used when the # socket was instantiated. def getpeername ::Socket.sockaddr_in(port, host) end - + # Alias to #read, but never returns nil (returns an empty string instead). def recv(n) read(n) || "" end - + def readpartial(n) recv(n) end - end end end diff --git a/lib/net/ssh/transport/cipher_factory.rb b/lib/net/ssh/transport/cipher_factory.rb index da3317f..bedf1ea 100644 --- a/lib/net/ssh/transport/cipher_factory.rb +++ b/lib/net/ssh/transport/cipher_factory.rb @@ -3,8 +3,8 @@ require 'net/ssh/transport/ctr.rb' require 'net/ssh/transport/key_expander' require 'net/ssh/transport/identity_cipher' -module Net - module SSH +module Net + module SSH module Transport # Implements a factory of OpenSSL cipher algorithms. class CipherFactory @@ -37,7 +37,7 @@ module Net return OpenSSL::Cipher.ciphers.include?(ossl_name) end - + # Retrieves a new instance of the named algorithm. The new instance # will be initialized using an iv and key generated from the given # iv, key, shared, hash and digester values. Additionally, the @@ -48,11 +48,11 @@ module Net return IdentityCipher if ossl_name == "none" cipher = OpenSSL::Cipher.new(ossl_name) - + cipher.send(options[:encrypt] ? :encrypt : :decrypt) - + cipher.padding = 0 - + if name =~ /-ctr(@openssh.org)?$/ if ossl_name !~ /-ctr/ cipher.extend(Net::SSH::Transport::CTR) @@ -61,14 +61,14 @@ module Net end end cipher.iv = Net::SSH::Transport::KeyExpander.expand_key(cipher.iv_len, options[:iv], options) - + key_len = cipher.key_len cipher.key_len = key_len cipher.key = Net::SSH::Transport::KeyExpander.expand_key(key_len, options[:key], options) - + return cipher end - + # Returns a two-element array containing the [ key-length, # block-size ] for the named cipher algorithm. If the cipher # algorithm is unknown, or is "none", 0 is returned for both elements @@ -83,7 +83,7 @@ module Net cipher = OpenSSL::Cipher.new(ossl_name) key_len = cipher.key_len cipher.key_len = key_len - + block_size = case ossl_name when /\-ctr/ @@ -91,7 +91,7 @@ module Net else cipher.block_size end - + result = [key_len, block_size] result << cipher.iv_len if options[:iv_len] end diff --git a/lib/net/ssh/transport/constants.rb b/lib/net/ssh/transport/constants.rb index 26747a6..b3c5fb4 100644 --- a/lib/net/ssh/transport/constants.rb +++ b/lib/net/ssh/transport/constants.rb @@ -1,5 +1,5 @@ -module Net - module SSH +module Net + module SSH module Transport module Constants #-- @@ -12,7 +12,7 @@ module Net DEBUG = 4 SERVICE_REQUEST = 5 SERVICE_ACCEPT = 6 - + #-- # Algorithm negotiation messages #++ diff --git a/lib/net/ssh/transport/identity_cipher.rb b/lib/net/ssh/transport/identity_cipher.rb index a23c85c..b8a90bc 100644 --- a/lib/net/ssh/transport/identity_cipher.rb +++ b/lib/net/ssh/transport/identity_cipher.rb @@ -1,5 +1,5 @@ -module Net - module SSH +module Net + module SSH module Transport # A cipher that does nothing but pass the data through, unchanged. This # keeps things in the code nice and clean when a cipher has not yet been @@ -10,42 +10,42 @@ module Net def block_size 8 end - + # Returns an arbitrary integer. def iv_len 4 end - + # Does nothing. Returns self. def encrypt self end - + # Does nothing. Returns self. def decrypt self end - + # Passes its single argument through unchanged. def update(text) text end - + # Returns the empty string. def final "" end - + # The name of this cipher, which is "identity". def name "identity" end - + # Does nothing. Returns nil. def iv=(v) nil end - + # Does nothing. Returns self. def reset self diff --git a/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb b/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb index d560da8..d74c521 100644 --- a/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +++ b/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb @@ -1,8 +1,8 @@ require 'net/ssh/transport/kex/diffie_hellman_group1_sha1' -module Net - module SSH - module Transport +module Net + module SSH + module Transport module Kex # A key-exchange service implementing the "diffie-hellman-group14-sha1" # key-exchange algorithm. (defined in RFC 4253) @@ -24,7 +24,7 @@ module Net "B5C55DF0" "6F4C52C9" "DE2BCBF6" "95581718" + "3995497C" "EA956AE5" "15D22618" "98FA0510" + "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF" - + # The radix in which P_s represents the value of P P_r = 16 diff --git a/lib/net/ssh/transport/key_expander.rb b/lib/net/ssh/transport/key_expander.rb index 108e9b9..93fbaf1 100644 --- a/lib/net/ssh/transport/key_expander.rb +++ b/lib/net/ssh/transport/key_expander.rb @@ -1,28 +1,27 @@ -module Net - module SSH +module Net + module SSH module Transport module KeyExpander - # Generate a key value in accordance with the SSH2 specification. # (RFC4253 7.2. "Output from Key Exchange") def self.expand_key(bytes, start, options={}) if bytes == 0 return "" end - + k = start[0, bytes] return k if k.length >= bytes - + digester = options[:digester] or raise 'No digester supplied' shared = options[:shared] or raise 'No shared secret supplied' hash = options[:hash] or raise 'No hash supplied' - + while k.length < bytes step = digester.digest(shared + hash + k) bytes_needed = bytes - k.length k << step[0, bytes_needed] end - + return k end end diff --git a/lib/net/ssh/transport/server_version.rb b/lib/net/ssh/transport/server_version.rb index ba37beb..82de8b0 100644 --- a/lib/net/ssh/transport/server_version.rb +++ b/lib/net/ssh/transport/server_version.rb @@ -2,8 +2,8 @@ require 'net/ssh/errors' require 'net/ssh/loggable' require 'net/ssh/version' -module Net - module SSH +module Net + module SSH module Transport # Negotiates the SSH protocol version and trades information about server # and client. This is never used directly--it is always called by the @@ -14,16 +14,16 @@ module Net # the authoritative reference for any queries regarding the version in effect. class ServerVersion include Loggable - + # The SSH version string as reported by Net::SSH PROTO_VERSION = "SSH-2.0-Ruby/Net::SSH_#{Net::SSH::Version::CURRENT} #{RUBY_PLATFORM}" - + # Any header text sent by the server prior to sending the version. attr_reader :header - + # The version string reported by the server. attr_reader :version - + # Instantiates a new ServerVersion and immediately (and synchronously) # negotiates the SSH protocol in effect, using the given socket. def initialize(socket, logger, timeout = nil) @@ -32,19 +32,19 @@ module Net @logger = logger negotiate!(socket, timeout) end - + private - + # Negotiates the SSH protocol to use, via the given socket. If the server # reports an incompatible SSH version (e.g., SSH1), this will raise an # exception. def negotiate!(socket, timeout) info { "negotiating protocol version" } - + debug { "local is `#{PROTO_VERSION}'" } socket.write "#{PROTO_VERSION}\r\n" socket.flush - + raise Net::SSH::ConnectionTimeout, "timeout during server version negotiating" if timeout && !IO.select([socket], nil, nil, timeout) loop do @@ -63,12 +63,12 @@ module Net @header << @version end - + @version.chomp! debug { "remote is `#{@version}'" } - + raise Net::SSH::Exception, "incompatible SSH version `#{@version}'" unless @version.match(/^SSH-(1\.99|2\.0)-/) - + raise Net::SSH::ConnectionTimeout, "timeout during client version negotiating" if timeout && !IO.select(nil, [socket], nil, timeout) end end diff --git a/lib/net/ssh/transport/state.rb b/lib/net/ssh/transport/state.rb index 0eaa78a..8f5fd8f 100644 --- a/lib/net/ssh/transport/state.rb +++ b/lib/net/ssh/transport/state.rb @@ -2,8 +2,8 @@ require 'zlib' require 'net/ssh/transport/cipher_factory' require 'net/ssh/transport/hmac' -module Net - module SSH +module Net + module SSH module Transport # Encapsulates state information about one end of an SSH connection. Such # state includes the packet sequence number, the algorithms in use, how @@ -13,46 +13,46 @@ module Net class State # The socket object that owns this state object. attr_reader :socket - + # The next packet sequence number for this socket endpoint. attr_reader :sequence_number - + # The hmac algorithm in use for this endpoint. attr_reader :hmac - + # The compression algorithm in use for this endpoint. attr_reader :compression - + # The compression level to use when compressing data (or nil, for the default). attr_reader :compression_level - + # The number of packets processed since the last call to #reset! attr_reader :packets - + # The number of data blocks processed since the last call to #reset! attr_reader :blocks - + # The cipher algorithm in use for this socket endpoint. attr_reader :cipher - + # The block size for the cipher attr_reader :block_size - + # The role that this state plays (either :client or :server) attr_reader :role - + # The maximum number of packets that this endpoint wants to process before # needing a rekey. attr_accessor :max_packets - + # The maximum number of blocks that this endpoint wants to process before # needing a rekey. attr_accessor :max_blocks - + # The user-specified maximum number of bytes that this endpoint ought to # process before needing a rekey. attr_accessor :rekey_limit - + # Creates a new state object, belonging to the given socket. Initializes # the algorithms to "none". def initialize(socket, role) @@ -66,7 +66,7 @@ module Net @compressor = @decompressor = nil @next_iv = "" end - + # A convenience method for quickly setting multiple values in a single # command. def set(values) @@ -75,19 +75,19 @@ module Net end reset! end - + def update_cipher(data) result = cipher.update(data) update_next_iv(role == :client ? result : data) return result end - + def final_cipher result = cipher.final update_next_iv(role == :client ? result : "", true) return result end - + # Increments the counters. The sequence number is incremented (and remapped # so it always fits in a 32-bit integer). The number of packets and blocks # are also incremented. @@ -96,18 +96,18 @@ module Net @packets += 1 @blocks += (packet_length + 4) / @block_size end - + # The compressor object to use when compressing data. This takes into account # the desired compression level. def compressor @compressor ||= Zlib::Deflate.new(compression_level || Zlib::DEFAULT_COMPRESSION) end - + # The decompressor object to use when decompressing data. def decompressor @decompressor ||= Zlib::Inflate.new(nil) end - + # Returns true if data compression/decompression is enabled. This will # return true if :standard compression is selected, or if :delayed # compression is selected and the :authenticated hint has been received @@ -115,7 +115,7 @@ module Net def compression? compression == :standard || (compression == :delayed && socket.hints[:authenticated]) end - + # Compresses the data. If no compression is in effect, this will just return # the data unmodified, otherwise it uses #compressor to compress the data. def compress(data) @@ -124,7 +124,7 @@ module Net compressor.deflate(data, Zlib::SYNC_FLUSH) end - + # Deompresses the data. If no compression is in effect, this will just return # the data unmodified, otherwise it uses #decompressor to decompress the data. def decompress(data) @@ -133,17 +133,17 @@ module Net decompressor.inflate(data) end - + # Resets the counters on the state object, but leaves the sequence_number # unchanged. It also sets defaults for and recomputes the max_packets and # max_blocks values. def reset! @packets = @blocks = 0 - + @max_packets ||= 1 << 31 - + @block_size = cipher.block_size - + if max_blocks.nil? # cargo-culted from openssh. the idea is that "the 2^(blocksize*2) # limit is too expensive for 3DES, blowfish, etc., so enforce a 1GB @@ -153,16 +153,16 @@ module Net else @max_blocks = (1 << 30) / @block_size end - + # if a limit on the # of bytes has been given, convert that into a # minimum number of blocks processed. - + @max_blocks = [@max_blocks, rekey_limit / @block_size].min if rekey_limit end - + cleanup end - + # Closes any the compressor and/or decompressor objects that have been # instantiated. def cleanup @@ -170,17 +170,17 @@ module Net @compressor.finish if !@compressor.finished? @compressor.close end - + if @decompressor # we call reset here so that we don't get warnings when we try to # close the decompressor @decompressor.reset @decompressor.close end - + @compressor = @decompressor = nil end - + # Returns true if the number of packets processed exceeds the maximum # number of packets, or if the number of blocks processed exceeds the # maximum number of blocks. @@ -188,18 +188,18 @@ module Net max_packets && packets > max_packets || max_blocks && blocks > max_blocks end - + private - + def update_next_iv(data, reset=false) @next_iv << data @next_iv = @next_iv[@next_iv.size - cipher.iv_len..-1] - + if reset cipher.reset cipher.iv = @next_iv end - + return data end end diff --git a/support/ssh_tunnel_bug.rb b/support/ssh_tunnel_bug.rb index d5fa09d..3f8f0ba 100755 --- a/support/ssh_tunnel_bug.rb +++ b/support/ssh_tunnel_bug.rb @@ -15,12 +15,12 @@ # visible_hostname netsshtest # * Start squid squid -N -d 1 -D # * Run this script -# * Configure browser proxy to use localhost with LOCAL_PORT. +# * Configure browser proxy to use localhost with LOCAL_PORT. # * Load any page, wait for it to load fully. If the page loads # correctly, move on. If not, something needs to be corrected. # * Refresh the page several times. This should cause this # script to failed with the error: "closed stream". You may -# need to try a few times. +# need to try a few times. # require 'highline/import' @@ -37,7 +37,7 @@ pass = ask("Password: ") { |q| q.echo = "*" } puts "Configure your browser proxy to localhost:#{LOCAL_PORT}" begin - session = Net::SSH.start(host, user, password: pass) + session = Net::SSH.start(host, user, password: pass) session.forward.local(LOCAL_PORT, host, PROXY_PORT) session.loop {true} rescue StandardError => e diff --git a/test/authentication/methods/common.rb b/test/authentication/methods/common.rb index 5546e1c..be9c11a 100644 --- a/test/authentication/methods/common.rb +++ b/test/authentication/methods/common.rb @@ -1,18 +1,18 @@ -module Authentication +module Authentication module Methods module Common include Net::SSH::Authentication::Constants - + private - + def socket(options={}) @socket ||= stub("socket", client_name: "me.ssh.test") end - + def transport(options={}) @transport ||= MockTransport.new(options.merge(socket: socket)) end - + def session(options={}) @session ||= begin sess = stub("auth-session", logger: nil, transport: transport(options)) @@ -22,13 +22,12 @@ module Authentication sess end end - + def reset_session(options = {}) @transport = nil @session = nil session(options) end - end end end diff --git a/test/authentication/methods/test_keyboard_interactive.rb b/test/authentication/methods/test_keyboard_interactive.rb index e18f02c..76d5272 100644 --- a/test/authentication/methods/test_keyboard_interactive.rb +++ b/test/authentication/methods/test_keyboard_interactive.rb @@ -2,18 +2,18 @@ require_relative '../../common' require 'net/ssh/authentication/methods/keyboard_interactive' require_relative 'common' -module Authentication +module Authentication module Methods class TestKeyboardInteractive < NetSSHTest include Common - + USERAUTH_INFO_REQUEST = 60 USERAUTH_INFO_RESPONSE = 61 - + def setup reset_subject({}) if defined? @subject && !@subject.options.empty? end - + def test_authenticate_should_raise_if_keyboard_interactive_disallowed transport.expect do |t,packet| assert_equal USERAUTH_REQUEST, packet.type @@ -22,18 +22,18 @@ module Authentication assert_equal "keyboard-interactive", packet.read_string assert_equal "", packet.read_string # language tags assert_equal "", packet.read_string # submethods - + t.return(USERAUTH_FAILURE, :string, "password") end - + assert_raises Net::SSH::Authentication::DisallowedMethod do subject.authenticate("ssh-connection", "jamis") end end - + def test_authenticate_should_be_false_if_given_password_is_not_accepted reset_subject(non_interactive: true) - + transport.expect do |t,packet| assert_equal USERAUTH_REQUEST, packet.type t.return(USERAUTH_INFO_REQUEST, :string, "", :string, "", :string, "", :long, 1, :string, "Password:", :bool, false) @@ -44,10 +44,10 @@ module Authentication t2.return(USERAUTH_FAILURE, :string, "keyboard-interactive") end end - + assert_equal false, subject.authenticate("ssh-connection", "jamis", "the-password") end - + def test_authenticate_should_be_true_if_given_password_is_accepted transport.expect do |t,packet| assert_equal USERAUTH_REQUEST, packet.type @@ -57,10 +57,10 @@ module Authentication t2.return(USERAUTH_SUCCESS) end end - + assert subject.authenticate("ssh-connection", "jamis", "the-password") end - + def test_authenticate_should_duplicate_password_as_needed_to_fill_request transport.expect do |t,packet| assert_equal USERAUTH_REQUEST, packet.type @@ -73,10 +73,10 @@ module Authentication t2.return(USERAUTH_SUCCESS) end end - + assert subject.authenticate("ssh-connection", "jamis", "the-password") end - + def test_authenticate_should_not_prompt_for_input_when_in_non_interactive_mode reset_subject(non_interactive: true) transport.expect do |t,packet| @@ -90,16 +90,16 @@ module Authentication t2.return(USERAUTH_SUCCESS) end end - + assert subject.authenticate("ssh-connection", "jamis", nil) - end - + end + def test_authenticate_should_prompt_for_input_when_password_is_not_given prompt = MockPrompt.new prompt.expects(:_ask).with("Name:", anything, true).returns("name") prompt.expects(:_ask).with("Password:", anything, false).returns("password") reset_subject(password_prompt: prompt) - + transport.expect do |t,packet| assert_equal USERAUTH_REQUEST, packet.type t.return(USERAUTH_INFO_REQUEST, :string, "", :string, "", :string, "", :long, 2, :string, "Name:", :bool, true, :string, "Password:", :bool, false) @@ -111,16 +111,16 @@ module Authentication t2.return(USERAUTH_SUCCESS) end end - + assert subject.authenticate("ssh-connection", "jamis", nil) end - + private - + def subject(options={}) @subject ||= Net::SSH::Authentication::Methods::KeyboardInteractive.new(session(options), options) end - + def reset_subject(options) @subject = nil reset_session(options) diff --git a/test/authentication/methods/test_none.rb b/test/authentication/methods/test_none.rb index 223b33c..bc71505 100644 --- a/test/authentication/methods/test_none.rb +++ b/test/authentication/methods/test_none.rb @@ -2,37 +2,37 @@ require 'common' require 'net/ssh/authentication/methods/none' require 'authentication/methods/common' -module Authentication +module Authentication module Methods class TestNone < NetSSHTest include Common - + def test_authenticate_should_raise_if_none_disallowed transport.expect do |t,packet| assert_equal USERAUTH_REQUEST, packet.type assert_equal "jamis", packet.read_string assert_equal "ssh-connection", packet.read_string assert_equal "none", packet.read_string - + t.return(USERAUTH_FAILURE, :string, "publickey") end - + assert_raises Net::SSH::Authentication::DisallowedMethod do subject.authenticate("ssh-connection", "jamis", "pass") end end - + def test_authenticate_should_return_true transport.expect do |t,packet| assert_equal USERAUTH_REQUEST, packet.type t.return(USERAUTH_SUCCESS) end - + assert subject.authenticate("ssh-connection", "", "") end - + private - + def subject(options={}) @subject ||= Net::SSH::Authentication::Methods::None.new(session(options), options) end diff --git a/test/authentication/methods/test_password.rb b/test/authentication/methods/test_password.rb index 5fee3aa..db520bd 100644 --- a/test/authentication/methods/test_password.rb +++ b/test/authentication/methods/test_password.rb @@ -3,11 +3,11 @@ require 'net/ssh/authentication/methods/password' require 'net/ssh/authentication/session' require 'authentication/methods/common' -module Authentication +module Authentication module Methods class TestPassword < NetSSHTest include Common - + def test_authenticate_should_raise_if_password_disallowed transport.expect do |t,packet| assert_equal USERAUTH_REQUEST, packet.type @@ -16,15 +16,15 @@ module Authentication assert_equal "password", packet.read_string assert_equal false, packet.read_bool assert_equal "the-password", packet.read_string - + t.return(USERAUTH_FAILURE, :string, "publickey") end - + assert_raises Net::SSH::Authentication::DisallowedMethod do subject.authenticate("ssh-connection", "jamis", "the-password") end end - + def test_authenticate_ask_for_password_for_second_time_when_password_is_incorrect transport.expect do |t,packet| assert_equal USERAUTH_REQUEST, packet.type @@ -34,7 +34,7 @@ module Authentication assert_equal false, packet.read_bool assert_equal "the-password", packet.read_string t.return(USERAUTH_FAILURE, :string, "publickey,password") - + t.expect do |_t2, packet2| assert_equal USERAUTH_REQUEST, packet2.type assert_equal "jamis", packet2.read_string @@ -45,12 +45,12 @@ module Authentication t.return(USERAUTH_SUCCESS) end end - + prompt = MockPrompt.new prompt.expects(:_ask).with("jamis@'s password:", { type: 'password', user: 'jamis', host: nil }, false).returns("the-password-2") subject(password_prompt: prompt).authenticate("ssh-connection", "jamis", "the-password") end - + def test_authenticate_ask_for_password_if_not_given transport.expect do |t,packet| assert_equal USERAUTH_REQUEST, packet.type @@ -61,33 +61,33 @@ module Authentication assert_equal "good-password", packet.read_string t.return(USERAUTH_SUCCESS) end - + transport.instance_eval { @host = 'testhost' } prompt = MockPrompt.new prompt.expects(:_ask).with("bill@testhost's password:", { type: 'password', user: 'bill', host: 'testhost' }, false).returns("good-password") subject(password_prompt: prompt).authenticate("ssh-connection", "bill", nil) end - + def test_authenticate_when_password_is_acceptible_should_return_true transport.expect do |t,packet| assert_equal USERAUTH_REQUEST, packet.type t.return(USERAUTH_SUCCESS) end - + assert subject.authenticate("ssh-connection", "jamis", "the-password") end - + def test_authenticate_should_return_false_if_password_change_request_is_received transport.expect do |t,packet| assert_equal USERAUTH_REQUEST, packet.type t.return(USERAUTH_PASSWD_CHANGEREQ, :string, "Change your password:", :string, "") end - + assert !subject.authenticate("ssh-connection", "jamis", "the-password") end - + private - + def subject(options={}) @subject ||= Net::SSH::Authentication::Methods::Password.new(session(options), options) end diff --git a/test/integration/mitm_server.rb b/test/integration/mitm_server.rb index e063687..365c318 100644 --- a/test/integration/mitm_server.rb +++ b/test/integration/mitm_server.rb @@ -52,7 +52,7 @@ class MitmServer < TCPServer r,_w,_e = IO.select([local, remote],nil,nil) if r.include? local begin - data = local.recv local_read_size + data = local.recv local_read_size rescue StandardError => e data = nil dlog "Local closed: #{e}" diff --git a/test/integration/test_curve25519sha256.rb b/test/integration/test_curve25519sha256.rb index 0b64b62..e6a152b 100644 --- a/test/integration/test_curve25519sha256.rb +++ b/test/integration/test_curve25519sha256.rb @@ -28,7 +28,6 @@ unless ENV['NET_SSH_NO_ED25519'] f.close start_sshd_7_or_later(config: config_lines) do |_pid, port| Timeout.timeout(4) do - # We have our own sshd, give it a chance to come up before # listening. ret = Net::SSH.start("localhost", "net_ssh_1", password: 'foopwd', port: port, user_known_hosts_file: [f.path]) do |ssh| @@ -39,7 +38,6 @@ unless ENV['NET_SSH_NO_ED25519'] rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH sleep 0.25 retry - end end end diff --git a/test/integration/test_ed25519_pkeys.rb b/test/integration/test_ed25519_pkeys.rb index 7ac5823..3358af7 100644 --- a/test/integration/test_ed25519_pkeys.rb +++ b/test/integration/test_ed25519_pkeys.rb @@ -10,7 +10,7 @@ unless ENV['NET_SSH_NO_ED25519'] # and usually connecting to net_ssh_2 user password foo2pwd class TestED25519PKeys < NetSSHTest include IntegrationTestHelpers - + def test_in_file_no_password Dir.mktmpdir do |dir| sh "rm -rf #{dir}/id_rsa_ed25519 #{dir}/id_rsa_ed25519.pub" @@ -22,8 +22,8 @@ unless ENV['NET_SSH_NO_ED25519'] end assert_equal "hello from:net_ssh_1\n", ret end - end - + end + def test_ssh_agent Dir.mktmpdir do |dir| with_agent do @@ -31,10 +31,10 @@ unless ENV['NET_SSH_NO_ED25519'] sh "ssh-keygen -q -f #{dir}/id_rsa_ed25519 -t ed25519 -N 'pwd'" set_authorized_key('net_ssh_1',"#{dir}/id_rsa_ed25519.pub") ssh_add("#{dir}/id_rsa_ed25519","pwd") - + # TODO: fix bug in net ssh which reads public key even if private key is there sh "mv #{dir}/id_rsa_ed25519.pub #{dir}/id_rsa_ed25519.pub.hidden" - + ret = Net::SSH.start("localhost", "net_ssh_1") do |ssh| ssh.exec! 'echo "hello from:$USER"' end @@ -42,13 +42,13 @@ unless ENV['NET_SSH_NO_ED25519'] end end end - + def test_in_file_with_password Dir.mktmpdir do |dir| sh "rm -rf #{dir}/id_rsa_ed25519 #{dir}/id_rsa_ed25519.pub" sh "ssh-keygen -q -f #{dir}/id_rsa_ed25519 -t ed25519 -N 'pwd'" set_authorized_key('net_ssh_1',"#{dir}/id_rsa_ed25519.pub") - + # TODO: fix bug in net ssh which reads public key even if private key is there sh "mv #{dir}/id_rsa_ed25519.pub #{dir}/id_rsa_ed25519.pub.hidden" @@ -58,7 +58,7 @@ unless ENV['NET_SSH_NO_ED25519'] assert_equal "hello from:net_ssh_1\n", ret end end - + def test_with_only_ed25519_host_key config_lines = File.read('/etc/ssh/sshd_config').split("\n") config_lines = config_lines.map do |line| @@ -68,7 +68,7 @@ unless ENV['NET_SSH_NO_ED25519'] line end end - + Tempfile.open('empty_kh') do |f| f.close with_sshd_config(config_lines.join("\n")) do diff --git a/test/integration/test_forward.rb b/test/integration/test_forward.rb index b84422f..75ce62f 100644 --- a/test/integration/test_forward.rb +++ b/test/integration/test_forward.rb @@ -51,7 +51,6 @@ class ForwardTestBase < NetSSHTest Thread.start do loop do Thread.start(server.accept) do |client| - 10000.times do |i| client.puts "item#{i}" end @@ -59,7 +58,6 @@ class ForwardTestBase < NetSSHTest rescue StandardError exceptions << $! raise - end end end @@ -73,14 +71,12 @@ class TestForward < ForwardTestBase Thread.start do loop do Thread.start(server.accept) do |client| - client.recv(1024) client.setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, [1, 0].pack("ii")) client.close rescue StandardError exceptions << $! raise - end end end @@ -187,14 +183,12 @@ class TestForward < ForwardTestBase session.forward.local(local_port, localhost, remote_port) client_done = Queue.new Thread.start do - client = TCPSocket.new(localhost, local_port) client.recv(1024) client.close sleep(0.2) ensure client_done << true - end session.loop(0.1) { client_done.empty? } assert_equal "Broken pipe", server_exc.pop.to_s unless server_exc.empty? @@ -211,7 +205,6 @@ class TestForward < ForwardTestBase session.forward.local(local_port, localhost, remote_port) client_done = Queue.new Thread.start do - client = TCPSocket.new(localhost, local_port) client.recv(1024) client.setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, [1, 0].pack("ii")) @@ -219,7 +212,6 @@ class TestForward < ForwardTestBase sleep(0.1) ensure client_done << true - end session.loop(0.1) { client_done.empty? } assert_equal "Broken pipe", server_exc.pop.to_s unless server_exc.empty? @@ -235,7 +227,6 @@ class TestForward < ForwardTestBase session.forward.local(local_port, localhost, remote_port) client_done = Queue.new Thread.start do - client = TCPSocket.new(localhost, local_port) 1.times do |i| client.puts "item#{i}" @@ -244,7 +235,6 @@ class TestForward < ForwardTestBase sleep(0.1) ensure client_done << true - end session.loop(0.1) { client_done.empty? } end @@ -273,7 +263,6 @@ class TestForward < ForwardTestBase client.close rescue StandardError server_done << $! - end client_done = Queue.new got_remote_port = Queue.new @@ -284,14 +273,12 @@ class TestForward < ForwardTestBase session.loop(0.1) { got_remote_port.empty? } remote_port = got_remote_port.pop Thread.start do - client = TCPSocket.new(localhost, remote_port) client.write(message) client.close client_done << true rescue StandardError client_done << $! - end Timeout.timeout(5) do session.loop(0.1) { server_done.empty? } @@ -332,7 +319,6 @@ class TestForward < ForwardTestBase # read on forwarded port client_done = Queue.new Thread.start do - client = TCPSocket.new(localhost, local_port) client.read(6) proxy.close_all @@ -341,16 +327,13 @@ class TestForward < ForwardTestBase client_done << true rescue StandardError client_done << $! - end server_error = nil Timeout.timeout(5) do - session.loop(0.1) { true } rescue IOError, Errno::EBADF server_error = $! # puts "Error: #{$!} #{$!.backtrace.join("\n")}" - end begin Timeout.timeout(5) do @@ -378,7 +361,6 @@ class TestForward < ForwardTestBase # read on forwarded port client_done = Queue.new Thread.start do - client = TCPSocket.new(localhost, local_port) client.read(6) system("killall /bin/nc") @@ -387,7 +369,6 @@ class TestForward < ForwardTestBase client_done << true rescue StandardError client_done << $! - end Timeout.timeout(5) do begin @@ -415,20 +396,17 @@ class TestForward < ForwardTestBase client.close rescue StandardError server_done << $! - end client_done = Queue.new remote_port = server.addr[1] local_port = session.forward.local(0, localhost, remote_port) Thread.start do - client = TCPSocket.new(localhost, local_port) client.write(message) client.close client_done << true rescue StandardError client_done << $! - end Timeout.timeout(5) do session.loop(0.1) { server_done.empty? } @@ -454,14 +432,12 @@ class TestForward < ForwardTestBase session.loop(0.1) { got_remote_port.empty? } remote_port = got_remote_port.pop Thread.start do - client = TCPSocket.new(localhost, remote_port) data = client.read(4096) client.close client_done << data rescue StandardError client_done << $! - end Timeout.timeout(5) do session.loop(0.1) { client_done.empty? } @@ -482,14 +458,12 @@ class TestForward < ForwardTestBase remote_port = server.addr[1] local_port = session.forward.local(0, localhost, remote_port) Thread.start do - client = TCPSocket.new(localhost, local_port) data = client.read(4096) client.close client_done << data rescue StandardError client_done << $! - end Timeout.timeout(5) do session.loop(0.1) { client_done.empty? } @@ -500,14 +474,12 @@ class TestForward < ForwardTestBase def _run_reading_client(client_done, local_port) Thread.start do - client = TCPSocket.new(localhost, local_port) data = client.read(4096) client.close client_done << data rescue StandardError client_done << $! - end end @@ -619,14 +591,12 @@ class TestForwardOnUnixSockets < ForwardTestBase client_done = Queue.new Thread.start do - client = UNIXSocket.new(local_socket.path) client_data = client.recv(1024) client.close sleep(0.2) ensure client_done << true - end begin @@ -644,7 +614,7 @@ class TestForwardOnUnixSockets < ForwardTestBase def test_forward_local_unix_socket_to_remote_socket setup_ssh_env do start_sshd_7_or_later do |_pid, port| - session = + session = # We have our own sshd, give it a chance to come up before # listening. Timeout.timeout(4) do @@ -652,7 +622,6 @@ class TestForwardOnUnixSockets < ForwardTestBase rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH sleep 0.25 retry - end create_local_socket do |remote_socket| diff --git a/test/integration/test_hmac_etm.rb b/test/integration/test_hmac_etm.rb index a508061..0c7182c 100644 --- a/test/integration/test_hmac_etm.rb +++ b/test/integration/test_hmac_etm.rb @@ -34,7 +34,6 @@ class TestHMacEtm < NetSSHTest define_method "test_with_only_hmac_etm#{key}" do start_sshd_7_or_later(config: config_with_macs(variant)) do |_pid, port| Timeout.timeout(4) do - # We have our own sshd, give it a chance to come up before # listening. ret = Net::SSH.start( @@ -52,7 +51,6 @@ class TestHMacEtm < NetSSHTest rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH sleep 0.25 retry - end end end diff --git a/test/start/test_transport.rb b/test/start/test_transport.rb index 78e3280..e94f32b 100644 --- a/test/start/test_transport.rb +++ b/test/start/test_transport.rb @@ -5,19 +5,19 @@ module NetSSH class TestStart < NetSSHTest attr_reader :transport_session attr_reader :authentication_session - + def setup @transport_session = mock('transport_session') @authentication_session = mock('authentication_session') Net::SSH::Transport::Session.expects(new: transport_session) Net::SSH::Authentication::Session.expects(new: authentication_session) end - + def test_close_transport_when_authentication_fails authentication_session.expects(authenticate: false) - + transport_session.expects(:close).at_least_once - + begin Net::SSH.start('localhost', 'testuser') {} rescue Net::SSH::AuthenticationFailed diff --git a/test/transport/hmac/test_md5.rb b/test/transport/hmac/test_md5.rb index 714eee0..3188b04 100644 --- a/test/transport/hmac/test_md5.rb +++ b/test/transport/hmac/test_md5.rb @@ -3,36 +3,36 @@ require 'common' require 'net/ssh/transport/hmac/md5' -module Transport +module Transport module HMAC class TestMD5 < NetSSHTest def test_expected_digest_class assert_equal OpenSSL::Digest::MD5, subject.digest_class assert_equal OpenSSL::Digest::MD5, subject.new.digest_class end - + def test_expected_key_length assert_equal 16, subject.key_length assert_equal 16, subject.new.key_length end - + def test_expected_mac_length assert_equal 16, subject.mac_length assert_equal 16, subject.new.mac_length end - + def test_expected_digest hmac = subject.new("1234567890123456") assert_equal "\275\345\006\307y~Oi\035<.\341\031\250<\257", hmac.digest("hello world") end - + def test_key_should_be_truncated_to_required_length hmac = subject.new("12345678901234567890") assert_equal "1234567890123456", hmac.key end - + private - + def subject Net::SSH::Transport::HMAC::MD5 end diff --git a/test/transport/hmac/test_md5_96.rb b/test/transport/hmac/test_md5_96.rb index 13f4a8a..2b238e5 100644 --- a/test/transport/hmac/test_md5_96.rb +++ b/test/transport/hmac/test_md5_96.rb @@ -4,21 +4,21 @@ require 'common' require 'transport/hmac/test_md5' require 'net/ssh/transport/hmac/md5_96' -module Transport +module Transport module HMAC class TestMD5_96 < TestMD5 def test_expected_mac_length assert_equal 12, subject.mac_length assert_equal 12, subject.new.mac_length end - + def test_expected_digest hmac = subject.new("1234567890123456") assert_equal "\275\345\006\307y~Oi\035<.\341", hmac.digest("hello world") end - + private - + def subject Net::SSH::Transport::HMAC::MD5_96 end diff --git a/test/transport/hmac/test_none.rb b/test/transport/hmac/test_none.rb index c2661f8..812075e 100644 --- a/test/transport/hmac/test_none.rb +++ b/test/transport/hmac/test_none.rb @@ -1,31 +1,31 @@ require 'common' require 'net/ssh/transport/hmac/none' -module Transport +module Transport module HMAC class TestNone < NetSSHTest def test_expected_digest_class assert_nil subject.digest_class assert_nil subject.new.digest_class end - + def test_expected_key_length assert_equal 0, subject.key_length assert_equal 0, subject.new.key_length end - + def test_expected_mac_length assert_equal 0, subject.mac_length assert_equal 0, subject.new.mac_length end - + def test_expected_digest hmac = subject.new("1234567890123456") assert_equal "", hmac.digest("hello world") end - + private - + def subject Net::SSH::Transport::HMAC::None end diff --git a/test/transport/hmac/test_ripemd160.rb b/test/transport/hmac/test_ripemd160.rb index 63ebbbd..e082485 100644 --- a/test/transport/hmac/test_ripemd160.rb +++ b/test/transport/hmac/test_ripemd160.rb @@ -3,31 +3,31 @@ require 'common' require 'net/ssh/transport/hmac/ripemd160' -module Transport +module Transport module HMAC class TestRipemd160 < NetSSHTest def test_expected_digest_class assert_equal OpenSSL::Digest::RIPEMD160, subject.digest_class assert_equal OpenSSL::Digest::RIPEMD160, subject.new.digest_class end - + def test_expected_key_length assert_equal 20, subject.key_length assert_equal 20, subject.new.key_length end - + def test_expected_mac_length assert_equal 20, subject.mac_length assert_equal 20, subject.new.mac_length end - + def test_expected_digest hmac = subject.new("1234567890123456") assert_equal "\xE4\x10\t\xB3\xD8,\x14\xA0k\x10\xB5\x0F?\x0E\x96q\x02\x16;E", hmac.digest("hello world") end - + private - + def subject Net::SSH::Transport::HMAC::RIPEMD160 end diff --git a/test/transport/hmac/test_sha1.rb b/test/transport/hmac/test_sha1.rb index efb9f4e..4bf3b28 100644 --- a/test/transport/hmac/test_sha1.rb +++ b/test/transport/hmac/test_sha1.rb @@ -3,31 +3,31 @@ require 'common' require 'net/ssh/transport/hmac/sha1' -module Transport +module Transport module HMAC class TestSHA1 < NetSSHTest def test_expected_digest_class assert_equal OpenSSL::Digest::SHA1, subject.digest_class assert_equal OpenSSL::Digest::SHA1, subject.new.digest_class end - + def test_expected_key_length assert_equal 20, subject.key_length assert_equal 20, subject.new.key_length end - + def test_expected_mac_length assert_equal 20, subject.mac_length assert_equal 20, subject.new.mac_length end - + def test_expected_digest hmac = subject.new("1234567890123456") assert_equal "\000\004W\202\204+&\335\311\251P\266\250\214\276\206;\022U\365", hmac.digest("hello world") end - + private - + def subject Net::SSH::Transport::HMAC::SHA1 end diff --git a/test/transport/hmac/test_sha1_96.rb b/test/transport/hmac/test_sha1_96.rb index 1dcf0cd..cefc16f 100644 --- a/test/transport/hmac/test_sha1_96.rb +++ b/test/transport/hmac/test_sha1_96.rb @@ -4,21 +4,21 @@ require 'common' require 'transport/hmac/test_sha1' require 'net/ssh/transport/hmac/sha1_96' -module Transport +module Transport module HMAC class TestSHA1_96 < TestSHA1 def test_expected_mac_length assert_equal 12, subject.mac_length assert_equal 12, subject.new.mac_length end - + def test_expected_digest hmac = subject.new("1234567890123456") assert_equal "\000\004W\202\204+&\335\311\251P\266", hmac.digest("hello world") end - + private - + def subject Net::SSH::Transport::HMAC::SHA1_96 end diff --git a/test/transport/hmac/test_sha2_256_96.rb b/test/transport/hmac/test_sha2_256_96.rb index 3a659fc..4083b1a 100644 --- a/test/transport/hmac/test_sha2_256_96.rb +++ b/test/transport/hmac/test_sha2_256_96.rb @@ -4,21 +4,21 @@ require 'common' require 'transport/hmac/test_sha2_256' require 'net/ssh/transport/hmac/sha2_256_96' -module Transport +module Transport module HMAC class TestSHA2_256_96 < TestSHA2_256 def test_expected_mac_length assert_equal 12, subject.mac_length assert_equal 12, subject.new.mac_length end - + def test_expected_digest hmac = subject.new("1234567890123456") assert_equal "\x16^>\x9FhO}\xB1>(\xBAF", hmac.digest("hello world") end - + private - + def subject Net::SSH::Transport::HMAC::SHA2_256_96 end diff --git a/test/transport/hmac/test_sha2_512_96.rb b/test/transport/hmac/test_sha2_512_96.rb index 16732bf..a80bc2c 100644 --- a/test/transport/hmac/test_sha2_512_96.rb +++ b/test/transport/hmac/test_sha2_512_96.rb @@ -4,21 +4,21 @@ require 'common' require 'transport/hmac/test_sha2_512' require 'net/ssh/transport/hmac/sha2_512_96' -module Transport +module Transport module HMAC class TestSHA2_512_96 < TestSHA2_512 def test_expected_mac_length assert_equal 12, subject.mac_length assert_equal 12, subject.new.mac_length end - + def test_expected_digest hmac = subject.new("1234567890123456") assert_equal "^\xB6\"\xED\x8B\xC4\xDE\xD4\xCF\xD0\r\x18", hmac.digest("hello world") end - + private - + def subject Net::SSH::Transport::HMAC::SHA2_512_96 end diff --git a/test/transport/kex/test_diffie_hellman_group14_sha1.rb b/test/transport/kex/test_diffie_hellman_group14_sha1.rb index ac15266..9c06c0c 100644 --- a/test/transport/kex/test_diffie_hellman_group14_sha1.rb +++ b/test/transport/kex/test_diffie_hellman_group14_sha1.rb @@ -3,7 +3,7 @@ require 'net/ssh/transport/kex/diffie_hellman_group14_sha1' require_relative './test_diffie_hellman_group1_sha1' require 'ostruct' -module Transport +module Transport module Kex class TestDiffieHellmanGroup14SHA1 < TestDiffieHellmanGroup1SHA1 def subject diff --git a/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb b/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb index b709dda..29a7d36 100644 --- a/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +++ b/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb @@ -2,60 +2,60 @@ require 'common' require 'transport/kex/test_diffie_hellman_group1_sha1' require 'net/ssh/transport/kex/diffie_hellman_group_exchange_sha1' -module Transport +module Transport module Kex class TestDiffieHellmanGroupExchangeSHA1 < TestDiffieHellmanGroup1SHA1 KEXDH_GEX_GROUP = 31 KEXDH_GEX_INIT = 32 KEXDH_GEX_REPLY = 33 KEXDH_GEX_REQUEST = 34 - + def test_exchange_with_fewer_than_minimum_bits_uses_minimum_bits dh_options need_bytes: 20 assert_equal 1024, need_bits assert_nothing_raised { exchange! } end - + def test_exchange_with_optional_minimum_bits_declared dh_options minimum_dh_bits: 4096 assert_equal 4096, need_bits assert_nothing_raised { exchange! } end - + def test_exchange_with_fewer_than_maximum_bits_uses_need_bits dh_options need_bytes: 500 need_bits(8001) assert_nothing_raised { exchange! } end - + def test_exchange_with_more_than_maximum_bits_uses_maximum_bits dh_options need_bytes: 2000 need_bits(8192) assert_nothing_raised { exchange! } end - + def test_that_p_and_g_are_provided_by_the_server assert_nothing_raised { exchange! p: default_p + 2, g: 3 } assert_equal default_p + 2, dh.dh.p assert_equal 3, dh.dh.g end - + private - + def need_bits(bits=1024) @need_bits ||= need_minimum(bits) end - + def need_minimum(bits=1024) return @dh_options[:minimum_dh_bits] if @dh_options && @dh_options[:minimum_dh_bits] bits end - + def default_p 142326151570335518660743995281621698377057354949884468943021767573608899048361360422513557553514790045512299468953431585300812548859419857171094366358158903433167915517332113861059747425408670144201099811846875730766487278261498262568348338476437200556998366087779709990807518291581860338635288400119315130179 end - + def exchange!(options={}) connection.expect do |t, buffer| assert_equal KEXDH_GEX_REQUEST, buffer.type @@ -73,18 +73,18 @@ module Transport end end end - + dh.exchange_keys end - + def subject Net::SSH::Transport::Kex::DiffieHellmanGroupExchangeSHA1 end - + def digest_type OpenSSL::Digest::SHA1 end - + def session_id @session_id ||= begin buffer = Net::SSH::Buffer.from(:string, packet_data[:client_version_string], diff --git a/test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb b/test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb index 95f4152..d3d6d76 100644 --- a/test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb +++ b/test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb @@ -2,15 +2,15 @@ require 'common' require 'net/ssh/transport/kex/diffie_hellman_group_exchange_sha1' require 'transport/kex/test_diffie_hellman_group_exchange_sha1' -module Transport +module Transport module Kex class TestDiffieHellmanGroupExchangeSHA256 < TestDiffieHellmanGroupExchangeSHA1 private - + def subject Net::SSH::Transport::Kex::DiffieHellmanGroupExchangeSHA256 end - + def digest_type OpenSSL::Digest::SHA256 end diff --git a/test/transport/test_state.rb b/test/transport/test_state.rb index b08fda7..389f012 100644 --- a/test/transport/test_state.rb +++ b/test/transport/test_state.rb @@ -114,7 +114,7 @@ module Transport end def test_compress_when_compression_is_enabled_should_return_compressed_text - state.set compression: :standard + state.set compression: :standard # JRuby Zlib implementation (1.4 & 1.5) does not have byte-to-byte compatibility with MRI's. # skip this test under JRuby. return if defined?(JRUBY_VERSION) @@ -123,7 +123,7 @@ module Transport end def test_decompress_when_compression_is_enabled_should_return_decompressed_text - state.set compression: :standard + state.set compression: :standard # JRuby Zlib implementation (1.4 & 1.5) does not have byte-to-byte compatibility with MRI's. # skip this test under JRuby. return if defined?(JRUBY_VERSION) diff --git a/test/win_integration/test_pageant.rb b/test/win_integration/test_pageant.rb index f87fe59..b7e89fa 100644 --- a/test/win_integration/test_pageant.rb +++ b/test/win_integration/test_pageant.rb @@ -15,21 +15,21 @@ module Authentication ensure Process.kill(9, pageant_pid) end - + def test_agent_should_be_able_to_negotiate_with_pagent with_pagent do agent.negotiate! end end - + def test_agent_should_raise_without_pagent assert_raises Net::SSH::Authentication::AgentNotAvailable do agent.negotiate! end end - + private - + def agent(auto=:connect) @agent ||= begin agent = Net::SSH::Authentication::Agent.new |