local stdnse = require "stdnse"
local table = require "table"
local libssh2 = stdnse.silent_require "libssh2"
SSHConnection = {}
function SSHConnection:new ()
  local o = {}
  setmetatable(o, self)
  self.__index = self
  return o
end
function SSHConnection:connect (host, port)
  self.session = libssh2.session_open(host, port.number)
  if self.session then
    return true
  end
end
function SSHConnection:connect_pcall (host, port)
  local status, err
  status, self.session, err = pcall(libssh2.session_open, host, port.number)
  return status, err
end
function SSHConnection:run_remote (cmd)
  if not (self.session and self.authenticated) then
    return false
  end
  local channel = libssh2.open_channel(self.session)
  libssh2.channel_exec(self.session, channel, cmd)
  libssh2.channel_send_eof(self.session, channel)
  local buff = {}
  local data = ""
  while not libssh2.channel_eof(channel) do
    data = libssh2.channel_read(self.session, channel)
    if data then
      table.insert(buff, data)
    end
  end
  return table.concat(buff)
end
function SSHConnection:password_auth (username, password)
  if not self.session then
    return false
  end
  if libssh2.userauth_password(self.session, username, password) then
    self.authenticated = true
    return true
  else
    return false
  end
end
function SSHConnection:publickey_auth (username, privatekey_file, passphrase)
  if not self.session then
    return false
  end
  if libssh2.userauth_publickey(self.session, username, privatekey_file, passphrase or "") then
    self.authenticated = true
    return true
  else
    return false
  end
end
function SSHConnection:disconnect ()
  if self.session then
    libssh2.session_close(self.session)
  end
end
function SSHConnection:set_timeout (ssh_timeout)
  if self.session then
    libssh2.set_timeout(self.session, ssh_timeout)
  end
end
function SSHConnection:list (username)
  if not self.session then
    return false
  end
  local status, methods = pcall(libssh2.userauth_list, self.session, username)
  if status then
    return methods
  end
  return false
end
function SSHConnection:read_publickey (publickey)
  local status, result = pcall(libssh2.read_publickey, publickey)
  return status, result
end
function SSHConnection:publickey_canauth (username, key)
  local status, err
  if self.session then
    status, err = pcall(libssh2.publickey_canauth, self.session, username, key)
    if status then
      status = err
      err = nil
    end
  else
    status = false
    err = "No session established"
  end
  return status, err
end
return _ENV
