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[
  metadata.json wp_fingerprints.json
  timthumbs-v3.txt config_backups.txt db_exports.txt
  dynamic_finders.yml LICENSE sponsor.txt
].freeze
OLD_FILES =
%w[
  wordpress.db user-agents.txt dynamic_finders_01.yml
  wordpresses.json plugins.json themes.json
].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(repo_directory) ⇒ Updater

Returns a new instance of Updater.



22
23
24
25
26
27
28
29
30
# 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)

  raise "#{repo_directory} is not writable" unless repo_directory.writable?

  delete_old_files
end

Instance Attribute Details

#repo_directoryObject (readonly)

Returns the value of attribute repo_directory.



20
21
22
# File 'lib/wpscan/db/updater.rb', line 20

def repo_directory
  @repo_directory
end

Instance Method Details

#backup_file_path(filename) ⇒ String

Returns:

  • (String)


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

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

#create_backup(filename) ⇒ Object



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

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



120
121
122
# File 'lib/wpscan/db/updater.rb', line 120

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



34
35
36
37
38
# File 'lib/wpscan/db/updater.rb', line 34

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:



125
126
127
128
129
130
131
132
133
134
135
# File 'lib/wpscan/db/updater.rb', line 125

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_updateTime?

Returns:

  • (Time, nil)


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

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)


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

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

#local_file_checksum(filename) ⇒ Object



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

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

#local_file_path(filename) ⇒ String

Returns:

  • (String)


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

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

#missing_files?Boolean

Returns:

  • (Boolean)


60
61
62
63
64
65
# File 'lib/wpscan/db/updater.rb', line 60

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

#outdated?Boolean

Returns:

  • (Boolean)


53
54
55
56
57
# File 'lib/wpscan/db/updater.rb', line 53

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:



85
86
87
88
89
90
91
92
# File 'lib/wpscan/db/updater.rb', line 85

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

Returns The raw file URL associated with the given filename.

Returns:

  • (String)

    The raw file URL associated with the given filename



80
81
82
# File 'lib/wpscan/db/updater.rb', line 80

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

#request_paramsHash

Note:

Those params can’t be overriden by CLI options

Returns The params for Typhoeus::Request.

Returns:

  • (Hash)

    The params for Typhoeus::Request



69
70
71
72
73
74
75
76
77
# File 'lib/wpscan/db/updater.rb', line 69

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



114
115
116
117
118
# File 'lib/wpscan/db/updater.rb', line 114

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



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/wpscan/db/updater.rb', line 138

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