Class: WPScan::DB::Updater

Inherits:
Object
  • Object
show all
Defined in:
lib/wpscan/db/updater.rb

Overview

Class used to perform DB updates :nocov:

Constant Summary collapse

FILES =

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

%w[
  plugins.json themes.json wordpresses.json
  timthumbs-v3.txt user-agents.txt config_backups.txt
  dynamic_finders.yml wp_fingerprints.json LICENSE
].freeze
OLD_FILES =
%w[wordpress.db dynamic_finders_01.yml].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(repo_directory) ⇒ Updater

Returns a new instance of Updater.



17
18
19
20
21
22
23
24
25
# File 'lib/wpscan/db/updater.rb', line 17

def initialize(repo_directory)
  @repo_directory = repo_directory

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

  raise "#{repo_directory} is not writable" unless Pathname.new(repo_directory).writable?

  delete_old_files
end

Instance Attribute Details

#repo_directoryObject (readonly)

Returns the value of attribute repo_directory.



15
16
17
# File 'lib/wpscan/db/updater.rb', line 15

def repo_directory
  @repo_directory
end

Instance Method Details

#backup_file_path(filename) ⇒ Object



96
97
98
# File 'lib/wpscan/db/updater.rb', line 96

def backup_file_path(filename)
  File.join(repo_directory, "#{filename}.back")
end

#create_backup(filename) ⇒ Object



100
101
102
103
# File 'lib/wpscan/db/updater.rb', line 100

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) ⇒ Object



110
111
112
# File 'lib/wpscan/db/updater.rb', line 110

def delete_backup(filename)
  FileUtils.rm(backup_file_path(filename))
end

#delete_old_filesObject

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



29
30
31
32
33
# File 'lib/wpscan/db/updater.rb', line 29

def delete_old_files
  OLD_FILES.each do |old_file|
    FileUtils.remove_file(local_file_path(old_file), true)
  end
end

#download(filename) ⇒ String

Returns The checksum of the downloaded file.

Returns:

  • (String)

    The checksum of the downloaded file

Raises:



115
116
117
118
119
120
121
122
123
124
125
# File 'lib/wpscan/db/updater.rb', line 115

def download(filename)
  file_path = local_file_path(filename)
  file_url  = remote_file_url(filename)

  res = Browser.get(file_url, request_params)
  raise DownloadError, res if res.timed_out? || res.code != 200

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

  local_file_checksum(filename)
end

#last_updateTime?

Returns:

  • (Time, nil)


36
37
38
39
40
# File 'lib/wpscan/db/updater.rb', line 36

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_fileString

Returns:

  • (String)


43
44
45
# File 'lib/wpscan/db/updater.rb', line 43

def last_update_file
  @last_update_file ||= File.join(repo_directory, '.last_update')
end

#local_file_checksum(filename) ⇒ Object



92
93
94
# File 'lib/wpscan/db/updater.rb', line 92

def local_file_checksum(filename)
  Digest::SHA512.file(local_file_path(filename)).hexdigest
end

#local_file_path(filename) ⇒ Object



88
89
90
# File 'lib/wpscan/db/updater.rb', line 88

def local_file_path(filename)
  File.join(repo_directory, filename.to_s)
end

#missing_files?Boolean

Returns:

  • (Boolean)


55
56
57
58
59
60
# File 'lib/wpscan/db/updater.rb', line 55

def missing_files?
  FILES.each do |file|
    return true unless File.exist?(File.join(repo_directory, file))
  end
  false
end

#outdated?Boolean

Returns:

  • (Boolean)


48
49
50
51
52
# File 'lib/wpscan/db/updater.rb', line 48

def outdated?
  date = last_update

  date.nil? || date < 5.days.ago
end

#remote_file_checksum(filename) ⇒ String

Returns The checksum of the associated remote filename.

Returns:

  • (String)

    The checksum of the associated remote filename

Raises:



80
81
82
83
84
85
86
# File 'lib/wpscan/db/updater.rb', line 80

def remote_file_checksum(filename)
  url = "#{remote_file_url(filename)}.sha512"

  res = Browser.get(url, request_params)
  raise DownloadError, res if res.timed_out? || res.code != 200
  res.body.chomp
end

#remote_file_url(filename) ⇒ String

Returns The raw file URL associated with the given filename.

Returns:

  • (String)

    The raw file URL associated with the given filename



75
76
77
# File 'lib/wpscan/db/updater.rb', line 75

def remote_file_url(filename)
  "https://data.wpscan.org/#{filename}"
end

#request_paramsHash

Returns The params for Typhoeus::Request.

Returns:

  • (Hash)

    The params for Typhoeus::Request



63
64
65
66
67
68
69
70
71
72
# File 'lib/wpscan/db/updater.rb', line 63

def request_params
  {
    ssl_verifyhost: 2,
    ssl_verifypeer: true,
    timeout: 300,
    connecttimeout: 120,
    accept_encoding: 'gzip, deflate',
    cache_ttl: 0
  }
end

#restore_backup(filename) ⇒ Object



105
106
107
108
# File 'lib/wpscan/db/updater.rb', line 105

def restore_backup(filename)
  return unless File.exist?(backup_file_path(filename))
  FileUtils.cp(backup_file_path(filename), local_file_path(filename))
end

#updateArray<String>

Returns The filenames updated.

Returns:

  • (Array<String>)

    The filenames updated



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/wpscan/db/updater.rb', line 128

def update
  updated = []

  FILES.each do |filename|
    begin
      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 "#{filename}: checksums do not match" 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
  end

  File.write(last_update_file, Time.now)

  updated
end