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_01.yml wp_fingerprints.json LICENSE
].freeze
OLD_FILES =
%w[wordpress.db dynamic_finders.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
# 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 => 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