class WPScan::DB::Updater

Class used to perform DB updates :nocov:

Constants

FILES

/!\ Might want to also update the Enumeration#cli_options when some filenames are changed here

OLD_FILES

Attributes

repo_directory[R]

Public Class Methods

new(repo_directory) click to toggle source
# File lib/wpscan/db/updater.rb, line 22
def initialize(repo_directory)
  @repo_directory = Pathname.new(repo_directory).expand_path

  FileUtils.mkdir_p(repo_directory.to_s) unless Dir.exist?(repo_directory.to_s)

  # When --no-update is passed, return to avoid raising an error if the directory is not writable
  # Mainly there for Homebrew: https://github.com/wpscanteam/wpscan/pull/1455
  return if ParsedCli.update == false

  unless repo_directory.writable?
    raise "#{repo_directory} is not writable (uid: #{Process.uid}, gid: #{Process.gid})"
  end

  delete_old_files
end

Public Instance Methods

backup_file_path(filename) click to toggle source

@return [ String ]

# File lib/wpscan/db/updater.rb, line 110
def backup_file_path(filename)
  repo_directory.join("#{filename}.back").to_s
end
create_backup(filename) click to toggle source
# File lib/wpscan/db/updater.rb, line 114
def create_backup(filename)
  return unless File.exist?(local_file_path(filename))

  FileUtils.cp(local_file_path(filename), backup_file_path(filename))
end
delete_backup(filename) click to toggle source
# File lib/wpscan/db/updater.rb, line 126
def delete_backup(filename)
  FileUtils.rm(backup_file_path(filename))
end
delete_old_files() click to toggle source

Removes DB files which are no longer used this doesn't raise errors if they don't exist

# File lib/wpscan/db/updater.rb, line 40
def delete_old_files
  OLD_FILES.each do |old_file|
    FileUtils.remove_file(local_file_path(old_file), true)
  end
end
download(filename) click to toggle source

@return [ String ] The checksum of the downloaded file

# File lib/wpscan/db/updater.rb, line 131
def download(filename)
  file_path = local_file_path(filename)
  file_url  = remote_file_url(filename)

  res = Typhoeus.get(file_url, request_params)
  raise Error::Download, res if res.timed_out? || res.code != 200

  File.open(file_path, 'wb') { |f| f.write(res.body) }

  local_file_checksum(filename)
end
last_update() click to toggle source

@return [ Time, nil ]

# File lib/wpscan/db/updater.rb, line 47
def last_update
  Time.parse(File.read(last_update_file))
rescue ArgumentError, Errno::ENOENT
  nil # returns nil if the file does not exist or contains invalid time data
end
last_update_file() click to toggle source

@return [ String ]

# File lib/wpscan/db/updater.rb, line 54
def last_update_file
  @last_update_file ||= repo_directory.join('.last_update').to_s
end
local_file_checksum(filename) click to toggle source
# File lib/wpscan/db/updater.rb, line 105
def local_file_checksum(filename)
  Digest::SHA512.file(local_file_path(filename)).hexdigest
end
local_file_path(filename) click to toggle source

@return [ String ]

# File lib/wpscan/db/updater.rb, line 101
def local_file_path(filename)
  repo_directory.join(filename.to_s).to_s
end
missing_files?() click to toggle source

@return [ Boolean ]

# File lib/wpscan/db/updater.rb, line 66
def missing_files?
  FILES.each do |file|
    return true unless File.exist?(repo_directory.join(file))
  end
  false
end
outdated?() click to toggle source

@return [ Boolean ]

# File lib/wpscan/db/updater.rb, line 59
def outdated?
  date = last_update

  date.nil? || date < 5.days.ago
end
remote_file_checksum(filename) click to toggle source

@return [ String ] The checksum of the associated remote filename

# File lib/wpscan/db/updater.rb, line 91
def remote_file_checksum(filename)
  url = "#{remote_file_url(filename)}.sha512"

  res = Typhoeus.get(url, request_params)
  raise Error::Download, res if res.timed_out? || res.code != 200

  res.body.chomp
end
remote_file_url(filename) click to toggle source

@return [ String ] The raw file URL associated with the given filename

# File lib/wpscan/db/updater.rb, line 86
def remote_file_url(filename)
  "https://data.wpscan.org/#{filename}"
end
request_params() click to toggle source

@return [ Hash ] The params for Typhoeus::Request @note Those params can't be overriden by CLI options

# File lib/wpscan/db/updater.rb, line 75
def request_params
  @request_params ||= Browser.instance.default_connect_request_params.merge(
    timeout: 600,
    connecttimeout: 300,
    accept_encoding: 'gzip, deflate',
    cache_ttl: 0,
    headers: { 'User-Agent' => Browser.instance.default_user_agent }
  )
end
restore_backup(filename) click to toggle source
# File lib/wpscan/db/updater.rb, line 120
def restore_backup(filename)
  return unless File.exist?(backup_file_path(filename))

  FileUtils.cp(backup_file_path(filename), local_file_path(filename))
end
update() click to toggle source

@return [ Array<String> ] The filenames updated

# File lib/wpscan/db/updater.rb, line 144
def update
  updated = []

  FILES.each do |filename|
    db_checksum = remote_file_checksum(filename)

    # Checking if the file needs to be updated
    next if File.exist?(local_file_path(filename)) && db_checksum == local_file_checksum(filename)

    create_backup(filename)
    dl_checksum = download(filename)

    raise Error::ChecksumsMismatch, filename unless dl_checksum == db_checksum

    updated << filename
  rescue StandardError => e
    restore_backup(filename)
    raise e
  ensure
    delete_backup(filename) if File.exist?(backup_file_path(filename))
  end

  File.write(last_update_file, Time.now)

  updated
end