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 wordpress.db LICENSE
].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(repo_directory) ⇒ Updater

Returns a new instance of Updater.



15
16
17
18
19
20
21
# File 'lib/wpscan/db/updater.rb', line 15

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

Instance Attribute Details

#repo_directoryObject (readonly)

Returns the value of attribute repo_directory.



13
14
15
# File 'lib/wpscan/db/updater.rb', line 13

def repo_directory
  @repo_directory
end

Instance Method Details

#backup_file_path(filename) ⇒ Object



84
85
86
# File 'lib/wpscan/db/updater.rb', line 84

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

#create_backup(filename) ⇒ Object



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

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



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

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

#download(filename) ⇒ String

Returns The checksum of the downloaded file.

Returns:

  • (String)

    The checksum of the downloaded file

Raises:



103
104
105
106
107
108
109
110
111
112
113
# File 'lib/wpscan/db/updater.rb', line 103

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)


24
25
26
27
28
# File 'lib/wpscan/db/updater.rb', line 24

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)


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

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

#local_file_checksum(filename) ⇒ Object



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

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

#local_file_path(filename) ⇒ Object



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

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

#missing_files?Boolean

Returns:

  • (Boolean)


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

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

#outdated?Boolean

Returns:

  • (Boolean)


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

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:



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

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



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

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



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

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



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

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



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/wpscan/db/updater.rb', line 116

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